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 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 "glvnd/libeglabi.h"
104
105    """.lstrip("\n"))
106
107    text += "enum {\n"
108    for (func, eglFunc) in functions:
109        text += generateGuardBegin(func, eglFunc)
110        text += "    __EGL_DISPATCH_" + func.name + ",\n"
111        text += generateGuardEnd(func, eglFunc)
112    text += "    __EGL_DISPATCH_COUNT\n"
113    text += "};\n"
114
115    for (func, eglFunc) in functions:
116        if eglFunc["inheader"]:
117            text += generateGuardBegin(func, eglFunc)
118            text += "{f.rt} EGLAPIENTRY {ex[prefix]}{f.name}({f.decArgs});\n".format(f=func, ex=eglFunc)
119            text += generateGuardEnd(func, eglFunc)
120
121    text += textwrap.dedent(r"""
122    #ifdef __cplusplus
123    }
124    #endif
125    #endif // G_EGLDISPATCH_STUBS_H
126    """)
127    return text
128
129def generateSource(functions):
130    # First, sort the function list by name.
131    text = ""
132    text += '#include "egldispatchstubs.h"\n'
133    text += '#include "g_egldispatchstubs.h"\n'
134    text += "\n"
135
136    for (func, eglFunc) in functions:
137        if eglFunc["method"] not in ("custom", "none"):
138            text += generateGuardBegin(func, eglFunc)
139            text += generateDispatchFunc(func, eglFunc)
140            text += generateGuardEnd(func, eglFunc)
141
142    text += "\n"
143    text += "const char * const __EGL_DISPATCH_FUNC_NAMES[__EGL_DISPATCH_COUNT + 1] = {\n"
144    for (func, eglFunc) in functions:
145        text += generateGuardBegin(func, eglFunc)
146        text += '    "' + func.name + '",\n'
147        text += generateGuardEnd(func, eglFunc)
148    text += "    NULL\n"
149    text += "};\n"
150
151    text += "const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[__EGL_DISPATCH_COUNT + 1] = {\n"
152    for (func, eglFunc) in functions:
153        text += generateGuardBegin(func, eglFunc)
154        if eglFunc["method"] != "none":
155            text += "    (__eglMustCastToProperFunctionPointerType) " + eglFunc.get("prefix", "") + func.name + ",\n"
156        else:
157            text += "    NULL, // " + func.name + "\n"
158        text += generateGuardEnd(func, eglFunc)
159    text += "    NULL\n"
160    text += "};\n"
161
162    return text
163
164def generateGuardBegin(func, eglFunc):
165    ext = eglFunc.get("extension")
166    if ext is not None:
167        return "#if " + ext + "\n"
168    else:
169        return ""
170
171def generateGuardEnd(func, eglFunc):
172    if eglFunc.get("extension") is not None:
173        return "#endif\n"
174    else:
175        return ""
176
177def generateDispatchFunc(func, eglFunc):
178    text = ""
179
180    if eglFunc.get("static"):
181        text += "static "
182    elif eglFunc.get("public"):
183        text += "PUBLIC "
184    text += textwrap.dedent(
185    r"""
186    {f.rt} EGLAPIENTRY {ef[prefix]}{f.name}({f.decArgs})
187    {{
188        typedef {f.rt} EGLAPIENTRY (* _pfn_{f.name})({f.decArgs});
189    """).lstrip("\n").format(f=func, ef=eglFunc)
190
191    if func.hasReturn():
192        text += "    {f.rt} _ret = {ef[retval]};\n".format(f=func, ef=eglFunc)
193
194    text += "    _pfn_{f.name} _ptr_{f.name} = (_pfn_{f.name}) ".format(f=func)
195    if eglFunc["method"] == "current":
196        text += "__eglDispatchFetchByCurrent(__EGL_DISPATCH_{f.name});\n".format(f=func)
197
198    elif eglFunc["method"] in ("display", "device"):
199        if eglFunc["method"] == "display":
200            lookupFunc = "__eglDispatchFetchByDisplay"
201            lookupType = "EGLDisplay"
202        else:
203            assert eglFunc["method"] == "device"
204            lookupFunc = "__eglDispatchFetchByDevice"
205            lookupType = "EGLDeviceEXT"
206
207        lookupArg = None
208        for arg in func.args:
209            if arg.type == lookupType:
210                lookupArg = arg.name
211                break
212        if lookupArg is None:
213            raise ValueError("Can't find %s argument for function %s" % (lookupType, func.name,))
214
215        text += "{lookupFunc}({lookupArg}, __EGL_DISPATCH_{f.name});\n".format(
216                f=func, lookupFunc=lookupFunc, lookupArg=lookupArg)
217    else:
218        raise ValueError("Unknown dispatch method: %r" % (eglFunc["method"],))
219
220    text += "    if(_ptr_{f.name} != NULL) {{\n".format(f=func)
221    text += "        "
222    if func.hasReturn():
223        text += "_ret = "
224    text += "_ptr_{f.name}({f.callArgs});\n".format(f=func)
225    text += "    }\n"
226
227    if func.hasReturn():
228        text += "    return _ret;\n"
229    text += "}\n"
230    return text
231
232def getDefaultReturnValue(typename):
233    if typename.endswith("*"):
234        return "NULL"
235    elif typename == "EGLDisplay":
236        return "EGL_NO_DISPLAY"
237    elif typename == "EGLContext":
238        return "EGL_NO_CONTEXT"
239    elif typename == "EGLSurface":
240        return "EGL_NO_SURFACE"
241    elif typename == "EGLBoolean":
242        return "EGL_FALSE";
243
244    return "0"
245
246if __name__ == "__main__":
247    main()
248
249