gen_egl_dispatch.py revision 01e04c3f
1#!/usr/bin/env python
2
3# (C) Copyright 2016, NVIDIA CORPORATION.
4# All Rights Reserved.
5#
6# Permission is hereby granted, free of charge, to any person obtaining a
7# copy of this software and associated documentation files (the "Software"),
8# to deal in the Software without restriction, including without limitation
9# on the rights to use, copy, modify, merge, publish, distribute, sub
10# license, and/or sell copies of the Software, and to permit persons to whom
11# the Software is furnished to do so, subject to the following conditions:
12#
13# The above copyright notice and this permission notice (including the next
14# paragraph) shall be included in all copies or substantial portions of the
15# Software.
16#
17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
20# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23# IN THE SOFTWARE.
24#
25# Authors:
26#    Kyle Brenneman <kbrenneman@nvidia.com>
27
28"""
29Generates dispatch functions for EGL.
30
31The list of functions and arguments is read from the Khronos's XML files, with
32additional information defined in the module eglFunctionList.
33"""
34
35import argparse
36import collections
37import imp
38import sys
39import textwrap
40
41import genCommon
42
43def main():
44    parser = argparse.ArgumentParser()
45    parser.add_argument("target", choices=("header", "source"),
46            help="Whether to build the source or header file.")
47    parser.add_argument("func_list_file", help="The function list .py file.")
48    parser.add_argument("xml_files", nargs="+", help="The XML files with the EGL function lists.")
49
50    args = parser.parse_args()
51
52    # The function list is a Python module, but it's specified on the command
53    # line.
54    eglFunctionList = imp.load_source("eglFunctionList", args.func_list_file)
55
56    xmlFunctions = genCommon.getFunctions(args.xml_files)
57    xmlByName = dict((f.name, f) for f in xmlFunctions)
58    functions = []
59    for (name, eglFunc) in eglFunctionList.EGL_FUNCTIONS:
60        func = xmlByName[name]
61        eglFunc = fixupEglFunc(func, eglFunc)
62        functions.append((func, eglFunc))
63
64    # Sort the function list by name.
65    functions = sorted(functions, key=lambda f: f[0].name)
66
67    if args.target == "header":
68        text = generateHeader(functions)
69    elif args.target == "source":
70        text = generateSource(functions)
71    sys.stdout.write(text)
72
73def fixupEglFunc(func, eglFunc):
74    result = dict(eglFunc)
75    if result.get("prefix") is None:
76        result["prefix"] = ""
77
78    if result.get("extension") is not None:
79        text = "defined(" + result["extension"] + ")"
80        result["extension"] = text
81
82    if result["method"] in ("none", "custom"):
83        return result
84
85    if result["method"] not in ("display", "device", "current"):
86        raise ValueError("Invalid dispatch method %r for function %r" % (result["method"], func.name))
87
88    if func.hasReturn():
89        if result.get("retval") is None:
90            result["retval"] = getDefaultReturnValue(func.rt)
91
92    return result
93
94def generateHeader(functions):
95    text = textwrap.dedent(r"""
96    #ifndef G_EGLDISPATCH_STUBS_H
97    #define G_EGLDISPATCH_STUBS_H
98
99    #ifdef __cplusplus
100    extern "C" {
101    #endif
102
103    #include <EGL/egl.h>
104    #include <EGL/eglext.h>
105    #include "glvnd/libeglabi.h"
106
107    """.lstrip("\n"))
108
109    text += "enum {\n"
110    for (func, eglFunc) in functions:
111        text += generateGuardBegin(func, eglFunc)
112        text += "    __EGL_DISPATCH_" + func.name + ",\n"
113        text += generateGuardEnd(func, eglFunc)
114    text += "    __EGL_DISPATCH_COUNT\n"
115    text += "};\n"
116
117    for (func, eglFunc) in functions:
118        if eglFunc["inheader"]:
119            text += generateGuardBegin(func, eglFunc)
120            text += "{f.rt} EGLAPIENTRY {ex[prefix]}{f.name}({f.decArgs});\n".format(f=func, ex=eglFunc)
121            text += generateGuardEnd(func, eglFunc)
122
123    text += textwrap.dedent(r"""
124    #ifdef __cplusplus
125    }
126    #endif
127    #endif // G_EGLDISPATCH_STUBS_H
128    """)
129    return text
130
131def generateSource(functions):
132    # First, sort the function list by name.
133    text = ""
134    text += '#include "egldispatchstubs.h"\n'
135    text += '#include "g_egldispatchstubs.h"\n'
136    text += "\n"
137
138    for (func, eglFunc) in functions:
139        if eglFunc["method"] not in ("custom", "none"):
140            text += generateGuardBegin(func, eglFunc)
141            text += generateDispatchFunc(func, eglFunc)
142            text += generateGuardEnd(func, eglFunc)
143
144    text += "\n"
145    text += "const char * const __EGL_DISPATCH_FUNC_NAMES[__EGL_DISPATCH_COUNT + 1] = {\n"
146    for (func, eglFunc) in functions:
147        text += generateGuardBegin(func, eglFunc)
148        text += '    "' + func.name + '",\n'
149        text += generateGuardEnd(func, eglFunc)
150    text += "    NULL\n"
151    text += "};\n"
152
153    text += "const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[__EGL_DISPATCH_COUNT + 1] = {\n"
154    for (func, eglFunc) in functions:
155        text += generateGuardBegin(func, eglFunc)
156        if eglFunc["method"] != "none":
157            text += "    (__eglMustCastToProperFunctionPointerType) " + eglFunc.get("prefix", "") + func.name + ",\n"
158        else:
159            text += "    NULL, // " + func.name + "\n"
160        text += generateGuardEnd(func, eglFunc)
161    text += "    NULL\n"
162    text += "};\n"
163
164    return text
165
166def generateGuardBegin(func, eglFunc):
167    ext = eglFunc.get("extension")
168    if ext is not None:
169        return "#if " + ext + "\n"
170    else:
171        return ""
172
173def generateGuardEnd(func, eglFunc):
174    if eglFunc.get("extension") is not None:
175        return "#endif\n"
176    else:
177        return ""
178
179def generateDispatchFunc(func, eglFunc):
180    text = ""
181
182    if eglFunc.get("static"):
183        text += "static "
184    elif eglFunc.get("public"):
185        text += "PUBLIC "
186    text += textwrap.dedent(
187    r"""
188    {f.rt} EGLAPIENTRY {ef[prefix]}{f.name}({f.decArgs})
189    {{
190        typedef {f.rt} EGLAPIENTRY (* _pfn_{f.name})({f.decArgs});
191    """).lstrip("\n").format(f=func, ef=eglFunc)
192
193    if func.hasReturn():
194        text += "    {f.rt} _ret = {ef[retval]};\n".format(f=func, ef=eglFunc)
195
196    text += "    _pfn_{f.name} _ptr_{f.name} = (_pfn_{f.name}) ".format(f=func)
197    if eglFunc["method"] == "current":
198        text += "__eglDispatchFetchByCurrent(__EGL_DISPATCH_{f.name});\n".format(f=func)
199
200    elif eglFunc["method"] in ("display", "device"):
201        if eglFunc["method"] == "display":
202            lookupFunc = "__eglDispatchFetchByDisplay"
203            lookupType = "EGLDisplay"
204        else:
205            assert eglFunc["method"] == "device"
206            lookupFunc = "__eglDispatchFetchByDevice"
207            lookupType = "EGLDeviceEXT"
208
209        lookupArg = None
210        for arg in func.args:
211            if arg.type == lookupType:
212                lookupArg = arg.name
213                break
214        if lookupArg is None:
215            raise ValueError("Can't find %s argument for function %s" % (lookupType, func.name,))
216
217        text += "{lookupFunc}({lookupArg}, __EGL_DISPATCH_{f.name});\n".format(
218                f=func, lookupFunc=lookupFunc, lookupArg=lookupArg)
219    else:
220        raise ValueError("Unknown dispatch method: %r" % (eglFunc["method"],))
221
222    text += "    if(_ptr_{f.name} != NULL) {{\n".format(f=func)
223    text += "        "
224    if func.hasReturn():
225        text += "_ret = "
226    text += "_ptr_{f.name}({f.callArgs});\n".format(f=func)
227    text += "    }\n"
228
229    if func.hasReturn():
230        text += "    return _ret;\n"
231    text += "}\n"
232    return text
233
234def getDefaultReturnValue(typename):
235    if typename.endswith("*"):
236        return "NULL"
237    elif typename == "EGLDisplay":
238        return "EGL_NO_DISPLAY"
239    elif typename == "EGLContext":
240        return "EGL_NO_CONTEXT"
241    elif typename == "EGLSurface":
242        return "EGL_NO_SURFACE"
243    elif typename == "EGLBoolean":
244        return "EGL_FALSE";
245
246    return "0"
247
248if __name__ == "__main__":
249    main()
250
251