libglvnd/src/generate/gen_egl_dispatch.py
2019-12-12 23:47:24 +00:00

223 lines
6.7 KiB
Python
Executable file

#!/usr/bin/env python
"""
Generates dispatch functions for EGL.
The list of functions and arguments is read from the Khronos's XML files, with
additional information defined in the module eglFunctionList.
"""
import argparse
import collections
import sys
import textwrap
import eglFunctionList
import genCommon
def main():
parser = argparse.ArgumentParser()
parser.add_argument("target", choices=("header", "source"),
help="Whether to build the source or header file.")
parser.add_argument("xml_files", nargs="+",
help="The XML files with the EGL function lists.")
args = parser.parse_args()
xmlFunctions = genCommon.getFunctions(args.xml_files)
xmlByName = dict((f.name, f) for f in xmlFunctions)
functions = []
for (name, eglFunc) in eglFunctionList.EGL_FUNCTIONS:
func = xmlByName[name]
eglFunc = fixupEglFunc(func, eglFunc)
functions.append((func, eglFunc))
# Sort the function list by name.
functions = sorted(functions, key=lambda f: f[0].name)
if args.target == "header":
text = generateHeader(functions)
elif args.target == "source":
text = generateSource(functions)
sys.stdout.write(text)
def fixupEglFunc(func, eglFunc):
result = dict(eglFunc)
if result.get("prefix") is None:
result["prefix"] = ""
if result.get("extension") is not None:
text = "defined(" + result["extension"] + ")"
result["extension"] = text
if result["method"] in ("none", "custom"):
return result
if result["method"] not in ("display", "device", "current"):
raise ValueError("Invalid dispatch method %r for function %r" % (result["method"], func.name))
if func.hasReturn():
if result.get("retval") is None:
result["retval"] = getDefaultReturnValue(func.rt)
return result
def generateHeader(functions):
text = textwrap.dedent(r"""
#ifndef G_EGLDISPATCH_STUBS_H
#define G_EGLDISPATCH_STUBS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "glvnd/libeglabi.h"
""".lstrip("\n"))
text += "enum {\n"
for (func, eglFunc) in functions:
text += generateGuardBegin(func, eglFunc)
text += " __EGL_DISPATCH_" + func.name + ",\n"
text += generateGuardEnd(func, eglFunc)
text += " __EGL_DISPATCH_COUNT\n"
text += "};\n"
for (func, eglFunc) in functions:
if eglFunc["inheader"]:
text += generateGuardBegin(func, eglFunc)
text += "{f.rt} EGLAPIENTRY {ex[prefix]}{f.name}({f.decArgs});\n".format(f=func, ex=eglFunc)
text += generateGuardEnd(func, eglFunc)
text += textwrap.dedent(r"""
#ifdef __cplusplus
}
#endif
#endif // G_EGLDISPATCH_STUBS_H
""")
return text
def generateSource(functions):
# First, sort the function list by name.
text = ""
text += '#include "egldispatchstubs.h"\n'
text += '#include "g_egldispatchstubs.h"\n'
text += '#include <stddef.h>\n'
text += "\n"
for (func, eglFunc) in functions:
if eglFunc["method"] not in ("custom", "none"):
text += generateGuardBegin(func, eglFunc)
text += generateDispatchFunc(func, eglFunc)
text += generateGuardEnd(func, eglFunc)
text += "\n"
text += "const char * const __EGL_DISPATCH_FUNC_NAMES[__EGL_DISPATCH_COUNT + 1] = {\n"
for (func, eglFunc) in functions:
text += generateGuardBegin(func, eglFunc)
text += ' "' + func.name + '",\n'
text += generateGuardEnd(func, eglFunc)
text += " NULL\n"
text += "};\n"
text += "const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[__EGL_DISPATCH_COUNT + 1] = {\n"
for (func, eglFunc) in functions:
text += generateGuardBegin(func, eglFunc)
if eglFunc["method"] != "none":
text += " (__eglMustCastToProperFunctionPointerType) " + eglFunc.get("prefix", "") + func.name + ",\n"
else:
text += " NULL, // " + func.name + "\n"
text += generateGuardEnd(func, eglFunc)
text += " NULL\n"
text += "};\n"
return text
def generateGuardBegin(func, eglFunc):
ext = eglFunc.get("extension")
if ext is not None:
return "#if " + ext + "\n"
else:
return ""
def generateGuardEnd(func, eglFunc):
if eglFunc.get("extension") is not None:
return "#endif\n"
else:
return ""
def generateDispatchFunc(func, eglFunc):
text = ""
if eglFunc.get("static"):
text += "static "
elif eglFunc.get("public"):
text += "PUBLIC "
text += textwrap.dedent(
r"""
{f.rt} EGLAPIENTRY {ef[prefix]}{f.name}({f.decArgs})
{{
typedef {f.rt} EGLAPIENTRY (* _pfn_{f.name})({f.decArgs});
""").lstrip("\n").format(f=func, ef=eglFunc)
if func.hasReturn():
text += " {f.rt} _ret = {ef[retval]};\n".format(f=func, ef=eglFunc)
text += " _pfn_{f.name} _ptr_{f.name} = (_pfn_{f.name}) ".format(f=func)
if eglFunc["method"] == "current":
text += "__eglDispatchFetchByCurrent(__EGL_DISPATCH_{f.name});\n".format(f=func)
elif eglFunc["method"] in ("display", "device"):
if eglFunc["method"] == "display":
lookupFunc = "__eglDispatchFetchByDisplay"
lookupType = "EGLDisplay"
else:
assert eglFunc["method"] == "device"
lookupFunc = "__eglDispatchFetchByDevice"
lookupType = "EGLDeviceEXT"
lookupArg = None
for arg in func.args:
if arg.type == lookupType:
lookupArg = arg.name
break
if lookupArg is None:
raise ValueError("Can't find %s argument for function %s" % (lookupType, func.name,))
text += "{lookupFunc}({lookupArg}, __EGL_DISPATCH_{f.name});\n".format(
f=func, lookupFunc=lookupFunc, lookupArg=lookupArg)
else:
raise ValueError("Unknown dispatch method: %r" % (eglFunc["method"],))
text += " if(_ptr_{f.name} != NULL) {{\n".format(f=func)
text += " "
if func.hasReturn():
text += "_ret = "
text += "_ptr_{f.name}({f.callArgs});\n".format(f=func)
text += " }\n"
if func.hasReturn():
text += " return _ret;\n"
text += "}\n"
return text
def getDefaultReturnValue(typename):
if typename.endswith("*"):
return "NULL"
elif typename == "EGLDisplay":
return "EGL_NO_DISPLAY"
elif typename == "EGLContext":
return "EGL_NO_CONTEXT"
elif typename == "EGLSurface":
return "EGL_NO_SURFACE"
elif typename == "EGLBoolean":
return "EGL_FALSE";
return "0"
if __name__ == "__main__":
main()