Blame src/generate/gen_egl_dispatch.py

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