1#!/usr/bin/env python3
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 eglFunctionList
38import sys
39import textwrap
40
41import os
42NEWAPI = os.path.join(os.path.dirname(__file__), "..", "..", "mapi", "new")
43sys.path.insert(0, NEWAPI)
44import genCommon
45
46def main():
47    parser = argparse.ArgumentParser()
48    parser.add_argument("target", choices=("header", "source"),
49            help="Whether to build the source or header file.")
50    parser.add_argument("xml_files", nargs="+", help="The XML files with the EGL function lists.")
51
52    args = parser.parse_args()
53
54    xmlFunctions = genCommon.getFunctions(args.xml_files)
55    xmlByName = dict((f.name, f) for f in xmlFunctions)
56    functions = []
57    for (name, eglFunc) in eglFunctionList.EGL_FUNCTIONS:
58        func = xmlByName[name]
59        eglFunc = fixupEglFunc(func, eglFunc)
60        functions.append((func, eglFunc))
61
62    # Sort the function list by name.
63    functions = sorted(functions, key=lambda f: f[0].name)
64
65    if args.target == "header":
66        text = generateHeader(functions)
67    elif args.target == "source":
68        text = generateSource(functions)
69    sys.stdout.write(text)
70
71def fixupEglFunc(func, eglFunc):
72    result = dict(eglFunc)
73    if result.get("prefix") is None:
74        result["prefix"] = ""
75
76    if result.get("extension") is not None:
77        text = "defined(" + result["extension"] + ")"
78        result["extension"] = text
79
80    if result["method"] in ("none", "custom"):
81        return result
82
83    if result["method"] not in ("display", "device", "current"):
84        raise ValueError("Invalid dispatch method %r for function %r" % (result["method"], func.name))
85
86    if func.hasReturn():
87        if result.get("retval") is None:
88            result["retval"] = getDefaultReturnValue(func.rt)
89
90    return result
91
92def generateHeader(functions):
93    text = textwrap.dedent(r"""
94    #ifndef G_EGLDISPATCH_STUBS_H
95    #define G_EGLDISPATCH_STUBS_H
96
97    #ifdef __cplusplus
98    extern "C" {
99    #endif
100
101    #include <EGL/egl.h>
102    #include <EGL/eglext.h>
103    #include <EGL/eglmesaext.h>
104    #include <EGL/eglextchromium.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 += '#include <stddef.h>\n'
137    text += "\n"
138
139    for (func, eglFunc) in functions:
140        if eglFunc["method"] not in ("custom", "none"):
141            text += generateGuardBegin(func, eglFunc)
142            text += generateDispatchFunc(func, eglFunc)
143            text += generateGuardEnd(func, eglFunc)
144
145    text += "\n"
146    text += "const char * const __EGL_DISPATCH_FUNC_NAMES[__EGL_DISPATCH_COUNT + 1] = {\n"
147    for (func, eglFunc) in functions:
148        text += generateGuardBegin(func, eglFunc)
149        text += '    "' + func.name + '",\n'
150        text += generateGuardEnd(func, eglFunc)
151    text += "    NULL\n"
152    text += "};\n"
153
154    text += "const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[__EGL_DISPATCH_COUNT + 1] = {\n"
155    for (func, eglFunc) in functions:
156        text += generateGuardBegin(func, eglFunc)
157        if eglFunc["method"] != "none":
158            text += "    (__eglMustCastToProperFunctionPointerType) " + eglFunc.get("prefix", "") + func.name + ",\n"
159        else:
160            text += "    NULL, // " + func.name + "\n"
161        text += generateGuardEnd(func, eglFunc)
162    text += "    NULL\n"
163    text += "};\n"
164
165    return text
166
167def generateGuardBegin(func, eglFunc):
168    ext = eglFunc.get("extension")
169    if ext is not None:
170        return "#if " + ext + "\n"
171    else:
172        return ""
173
174def generateGuardEnd(func, eglFunc):
175    if eglFunc.get("extension") is not None:
176        return "#endif\n"
177    else:
178        return ""
179
180def generateDispatchFunc(func, eglFunc):
181    text = ""
182
183    if eglFunc.get("static"):
184        text += "static "
185    elif eglFunc.get("public"):
186        text += "PUBLIC "
187    text += textwrap.dedent(
188    r"""
189    {f.rt} EGLAPIENTRY {ef[prefix]}{f.name}({f.decArgs})
190    {{
191        typedef {f.rt} EGLAPIENTRY (* _pfn_{f.name})({f.decArgs});
192    """).lstrip("\n").format(f=func, ef=eglFunc)
193
194    if func.hasReturn():
195        text += "    {f.rt} _ret = {ef[retval]};\n".format(f=func, ef=eglFunc)
196
197    text += "    _pfn_{f.name} _ptr_{f.name} = (_pfn_{f.name}) ".format(f=func)
198    if eglFunc["method"] == "current":
199        text += "__eglDispatchFetchByCurrent(__EGL_DISPATCH_{f.name});\n".format(f=func)
200
201    elif eglFunc["method"] in ("display", "device"):
202        if eglFunc["method"] == "display":
203            lookupFunc = "__eglDispatchFetchByDisplay"
204            lookupType = "EGLDisplay"
205        else:
206            assert eglFunc["method"] == "device"
207            lookupFunc = "__eglDispatchFetchByDevice"
208            lookupType = "EGLDeviceEXT"
209
210        lookupArg = None
211        for arg in func.args:
212            if arg.type == lookupType:
213                lookupArg = arg.name
214                break
215        if lookupArg is None:
216            raise ValueError("Can't find %s argument for function %s" % (lookupType, func.name,))
217
218        text += "{lookupFunc}({lookupArg}, __EGL_DISPATCH_{f.name});\n".format(
219                f=func, lookupFunc=lookupFunc, lookupArg=lookupArg)
220    else:
221        raise ValueError("Unknown dispatch method: %r" % (eglFunc["method"],))
222
223    text += "    if(_ptr_{f.name} != NULL) {{\n".format(f=func)
224    text += "        "
225    if func.hasReturn():
226        text += "_ret = "
227    text += "_ptr_{f.name}({f.callArgs});\n".format(f=func)
228    text += "    }\n"
229
230    if func.hasReturn():
231        text += "    return _ret;\n"
232    text += "}\n"
233    return text
234
235def getDefaultReturnValue(typename):
236    if typename.endswith("*"):
237        return "NULL"
238    elif typename == "EGLDisplay":
239        return "EGL_NO_DISPLAY"
240    elif typename == "EGLContext":
241        return "EGL_NO_CONTEXT"
242    elif typename == "EGLSurface":
243        return "EGL_NO_SURFACE"
244    elif typename == "EGLBoolean":
245        return "EGL_FALSE";
246
247    return "0"
248
249if __name__ == "__main__":
250    main()
251
252