d556a7782c9438f416213ca5e99b5f66eda8c2fe
[mesa.git] / src / egl / generate / gen_egl_dispatch.py
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 """
29 Generates dispatch functions for EGL.
30
31 The list of functions and arguments is read from the Khronos's XML files, with
32 additional information defined in the module eglFunctionList.
33 """
34
35 import argparse
36 import collections
37 import eglFunctionList
38 import sys
39 import textwrap
40
41 import genCommon
42
43 def 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("xml_files", nargs="+", help="The XML files with the EGL function lists.")
48
49 args = parser.parse_args()
50
51 xmlFunctions = genCommon.getFunctions(args.xml_files)
52 xmlByName = dict((f.name, f) for f in xmlFunctions)
53 functions = []
54 for (name, eglFunc) in eglFunctionList.EGL_FUNCTIONS:
55 func = xmlByName[name]
56 eglFunc = fixupEglFunc(func, eglFunc)
57 functions.append((func, eglFunc))
58
59 # Sort the function list by name.
60 functions = sorted(functions, key=lambda f: f[0].name)
61
62 if args.target == "header":
63 text = generateHeader(functions)
64 elif args.target == "source":
65 text = generateSource(functions)
66 sys.stdout.write(text)
67
68 def fixupEglFunc(func, eglFunc):
69 result = dict(eglFunc)
70 if result.get("prefix") is None:
71 result["prefix"] = ""
72
73 if result.get("extension") is not None:
74 text = "defined(" + result["extension"] + ")"
75 result["extension"] = text
76
77 if result["method"] in ("none", "custom"):
78 return result
79
80 if result["method"] not in ("display", "device", "current"):
81 raise ValueError("Invalid dispatch method %r for function %r" % (result["method"], func.name))
82
83 if func.hasReturn():
84 if result.get("retval") is None:
85 result["retval"] = getDefaultReturnValue(func.rt)
86
87 return result
88
89 def generateHeader(functions):
90 text = textwrap.dedent(r"""
91 #ifndef G_EGLDISPATCH_STUBS_H
92 #define G_EGLDISPATCH_STUBS_H
93
94 #ifdef __cplusplus
95 extern "C" {
96 #endif
97
98 #include <EGL/egl.h>
99 #include <EGL/eglext.h>
100 #include "glvnd/libeglabi.h"
101
102 """.lstrip("\n"))
103
104 text += "enum {\n"
105 for (func, eglFunc) in functions:
106 text += generateGuardBegin(func, eglFunc)
107 text += " __EGL_DISPATCH_" + func.name + ",\n"
108 text += generateGuardEnd(func, eglFunc)
109 text += " __EGL_DISPATCH_COUNT\n"
110 text += "};\n"
111
112 for (func, eglFunc) in functions:
113 if eglFunc["inheader"]:
114 text += generateGuardBegin(func, eglFunc)
115 text += "{f.rt} EGLAPIENTRY {ex[prefix]}{f.name}({f.decArgs});\n".format(f=func, ex=eglFunc)
116 text += generateGuardEnd(func, eglFunc)
117
118 text += textwrap.dedent(r"""
119 #ifdef __cplusplus
120 }
121 #endif
122 #endif // G_EGLDISPATCH_STUBS_H
123 """)
124 return text
125
126 def generateSource(functions):
127 # First, sort the function list by name.
128 text = ""
129 text += '#include "egldispatchstubs.h"\n'
130 text += '#include "g_egldispatchstubs.h"\n'
131 text += "\n"
132
133 for (func, eglFunc) in functions:
134 if eglFunc["method"] not in ("custom", "none"):
135 text += generateGuardBegin(func, eglFunc)
136 text += generateDispatchFunc(func, eglFunc)
137 text += generateGuardEnd(func, eglFunc)
138
139 text += "\n"
140 text += "const char * const __EGL_DISPATCH_FUNC_NAMES[__EGL_DISPATCH_COUNT + 1] = {\n"
141 for (func, eglFunc) in functions:
142 text += generateGuardBegin(func, eglFunc)
143 text += ' "' + func.name + '",\n'
144 text += generateGuardEnd(func, eglFunc)
145 text += " NULL\n"
146 text += "};\n"
147
148 text += "const __eglMustCastToProperFunctionPointerType __EGL_DISPATCH_FUNCS[__EGL_DISPATCH_COUNT + 1] = {\n"
149 for (func, eglFunc) in functions:
150 text += generateGuardBegin(func, eglFunc)
151 if eglFunc["method"] != "none":
152 text += " (__eglMustCastToProperFunctionPointerType) " + eglFunc.get("prefix", "") + func.name + ",\n"
153 else:
154 text += " NULL, // " + func.name + "\n"
155 text += generateGuardEnd(func, eglFunc)
156 text += " NULL\n"
157 text += "};\n"
158
159 return text
160
161 def generateGuardBegin(func, eglFunc):
162 ext = eglFunc.get("extension")
163 if ext is not None:
164 return "#if " + ext + "\n"
165 else:
166 return ""
167
168 def generateGuardEnd(func, eglFunc):
169 if eglFunc.get("extension") is not None:
170 return "#endif\n"
171 else:
172 return ""
173
174 def generateDispatchFunc(func, eglFunc):
175 text = ""
176
177 if eglFunc.get("static"):
178 text += "static "
179 elif eglFunc.get("public"):
180 text += "PUBLIC "
181 text += textwrap.dedent(
182 r"""
183 {f.rt} EGLAPIENTRY {ef[prefix]}{f.name}({f.decArgs})
184 {{
185 typedef {f.rt} EGLAPIENTRY (* _pfn_{f.name})({f.decArgs});
186 """).lstrip("\n").format(f=func, ef=eglFunc)
187
188 if func.hasReturn():
189 text += " {f.rt} _ret = {ef[retval]};\n".format(f=func, ef=eglFunc)
190
191 text += " _pfn_{f.name} _ptr_{f.name} = (_pfn_{f.name}) ".format(f=func)
192 if eglFunc["method"] == "current":
193 text += "__eglDispatchFetchByCurrent(__EGL_DISPATCH_{f.name});\n".format(f=func)
194
195 elif eglFunc["method"] in ("display", "device"):
196 if eglFunc["method"] == "display":
197 lookupFunc = "__eglDispatchFetchByDisplay"
198 lookupType = "EGLDisplay"
199 else:
200 assert eglFunc["method"] == "device"
201 lookupFunc = "__eglDispatchFetchByDevice"
202 lookupType = "EGLDeviceEXT"
203
204 lookupArg = None
205 for arg in func.args:
206 if arg.type == lookupType:
207 lookupArg = arg.name
208 break
209 if lookupArg is None:
210 raise ValueError("Can't find %s argument for function %s" % (lookupType, func.name,))
211
212 text += "{lookupFunc}({lookupArg}, __EGL_DISPATCH_{f.name});\n".format(
213 f=func, lookupFunc=lookupFunc, lookupArg=lookupArg)
214 else:
215 raise ValueError("Unknown dispatch method: %r" % (eglFunc["method"],))
216
217 text += " if(_ptr_{f.name} != NULL) {{\n".format(f=func)
218 text += " "
219 if func.hasReturn():
220 text += "_ret = "
221 text += "_ptr_{f.name}({f.callArgs});\n".format(f=func)
222 text += " }\n"
223
224 if func.hasReturn():
225 text += " return _ret;\n"
226 text += "}\n"
227 return text
228
229 def getDefaultReturnValue(typename):
230 if typename.endswith("*"):
231 return "NULL"
232 elif typename == "EGLDisplay":
233 return "EGL_NO_DISPLAY"
234 elif typename == "EGLContext":
235 return "EGL_NO_CONTEXT"
236 elif typename == "EGLSurface":
237 return "EGL_NO_SURFACE"
238 elif typename == "EGLBoolean":
239 return "EGL_FALSE";
240
241 return "0"
242
243 if __name__ == "__main__":
244 main()
245