EGL: Implement the libglvnd interface for EGL (v3)
[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 imp
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("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
73 def 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
94 def 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
131 def 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
166 def generateGuardBegin(func, eglFunc):
167 ext = eglFunc.get("extension")
168 if ext is not None:
169 return "#if " + ext + "\n"
170 else:
171 return ""
172
173 def generateGuardEnd(func, eglFunc):
174 if eglFunc.get("extension") is not None:
175 return "#endif\n"
176 else:
177 return ""
178
179 def 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
234 def 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
248 if __name__ == "__main__":
249 main()
250