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