blob: 55371ab1b595591fb8eceffede1ab236676c750b [file] [log] [blame]
Chia-I Wufb2559d2014-08-01 11:19:52 +08001#!/usr/bin/env python3
Chia-I Wu701f3f62014-09-02 08:32:09 +08002#
3# XGL
4#
5# Copyright (C) 2014 LunarG, Inc.
6#
7# Permission is hereby granted, free of charge, to any person obtaining a
8# copy of this software and associated documentation files (the "Software"),
9# to deal in the Software without restriction, including without limitation
10# the rights to use, copy, modify, merge, publish, distribute, sublicense,
11# and/or sell copies of the Software, and to permit persons to whom the
12# Software is furnished to do so, subject to the following conditions:
13#
14# The above copyright notice and this permission notice shall be included
15# in all copies or substantial portions of the 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 NONINFRINGEMENT. IN NO EVENT SHALL
20# THE AUTHORS OR COPYRIGHT HOLDERS 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
23# DEALINGS IN THE SOFTWARE.
24#
25# Authors:
26# Chia-I Wu <olv@lunarg.com>
Chia-I Wufb2559d2014-08-01 11:19:52 +080027
28import sys
29
30import xgl
31
Chia-I Wu6cdaedb2015-01-05 12:55:13 +080032def generate_get_proc_addr_check(name):
33 return " if (!%s || %s[0] != 'x' || %s[1] != 'g' || %s[2] != 'l')\n" \
34 " return NULL;" % ((name,) * 4)
35
Chia-I Wufb2559d2014-08-01 11:19:52 +080036class Subcommand(object):
37 def __init__(self, argv):
38 self.argv = argv
Chia-I Wuc4f24e82015-01-01 08:46:31 +080039 self.headers = xgl.headers
40 self.protos = xgl.protos
Chia-I Wufb2559d2014-08-01 11:19:52 +080041
42 def run(self):
Chia-I Wufb2559d2014-08-01 11:19:52 +080043 print(self.generate())
44
45 def generate(self):
46 copyright = self.generate_copyright()
47 header = self.generate_header()
48 body = self.generate_body()
49 footer = self.generate_footer()
50
51 contents = []
52 if copyright:
53 contents.append(copyright)
54 if header:
55 contents.append(header)
56 if body:
57 contents.append(body)
58 if footer:
59 contents.append(footer)
60
61 return "\n\n".join(contents)
62
63 def generate_copyright(self):
64 return """/* THIS FILE IS GENERATED. DO NOT EDIT. */
65
66/*
67 * XGL
68 *
69 * Copyright (C) 2014 LunarG, Inc.
70 *
71 * Permission is hereby granted, free of charge, to any person obtaining a
72 * copy of this software and associated documentation files (the "Software"),
73 * to deal in the Software without restriction, including without limitation
74 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
75 * and/or sell copies of the Software, and to permit persons to whom the
76 * Software is furnished to do so, subject to the following conditions:
77 *
78 * The above copyright notice and this permission notice shall be included
79 * in all copies or substantial portions of the Software.
80 *
81 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
82 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
83 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
84 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
85 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
86 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
87 * DEALINGS IN THE SOFTWARE.
88 */"""
89
90 def generate_header(self):
Chia-I Wu6bdf0192014-09-13 13:36:06 +080091 return "\n".join(["#include <" + h + ">" for h in self.headers])
Chia-I Wufb2559d2014-08-01 11:19:52 +080092
93 def generate_body(self):
94 pass
95
96 def generate_footer(self):
97 pass
98
Chia-I Wub3d5e192015-01-04 10:15:48 +080099class LoaderEntrypointsSubcommand(Subcommand):
Chia-I Wu2e4f5302015-01-02 00:21:24 +0800100 def generate_header(self):
Chia-I Wu5291c762015-04-11 15:34:07 +0800101 return "#include \"loader.h\""
Chia-I Wu2e4f5302015-01-02 00:21:24 +0800102
Chia-I Wu27697e42015-01-04 15:32:52 +0800103 def _is_dispatchable(self, proto):
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -0600104 if proto.name in ["GetProcAddr", "DestroyInstance", "EnumerateGpus",
105 "EnumerateLayers", "DbgRegisterMsgCallback",
106 "DbgUnregisterMsgCallback", "DbgSetGlobalOption"]:
Chia-I Wudf2d6392015-01-04 15:38:47 +0800107 return False
Chia-I Wu27697e42015-01-04 15:32:52 +0800108
Chia-I Wudf2d6392015-01-04 15:38:47 +0800109 in_objs = proto.object_in_params()
110 return in_objs and in_objs[0] == proto.params[0]
Chia-I Wu27697e42015-01-04 15:32:52 +0800111
Chia-I Wu327c3f52015-04-11 16:07:13 +0800112 def _generate_object_setup(self, proto):
113 method = "loader_init_data"
114 cond = "res == XGL_SUCCESS"
115
116 if "Get" in proto.name:
117 method = "loader_set_data"
118
119 setup = []
120
121 if proto.name == "AllocDescriptorSets":
122 psets = proto.params[-2].name
123 pcount = proto.params[-1].name
124 setup.append("uint32_t i;")
125 setup.append("for (i = 0; i < *%s; i++)" % pcount)
126 setup.append(" %s(%s[i], disp);" % (method, psets))
127 else:
128 obj_params = proto.object_out_params()
129 for param in obj_params:
130 setup.append("%s(*%s, disp);" % (method, param.name))
131
132 if setup:
133 joined = "\n ".join(setup)
134 setup = []
135 setup.append(" if (%s) {" % cond)
136 setup.append(" " + joined)
137 setup.append(" }")
138
139 return "\n".join(setup)
140
Chia-I Wu2e4f5302015-01-02 00:21:24 +0800141 def _generate_loader_dispatch_entrypoints(self, qual=""):
Chia-I Wu19300602014-08-04 08:03:57 +0800142 if qual:
143 qual += " "
144
Chia-I Wudac3e492014-08-02 23:49:43 +0800145 funcs = []
146 for proto in self.protos:
Chia-I Wu27697e42015-01-04 15:32:52 +0800147 if not self._is_dispatchable(proto):
Tobin Ehlisea7fe0b2014-11-12 11:47:07 -0700148 continue
Chia-I Wu327c3f52015-04-11 16:07:13 +0800149
150 func = []
151
152 obj_setup = self._generate_object_setup(proto)
153
154 func.append(qual + proto.c_func(prefix="xgl", attr="XGLAPI"))
155 func.append("{")
156
157 # declare local variables
158 func.append(" const XGL_LAYER_DISPATCH_TABLE *disp;")
159 if proto.ret != 'void' and obj_setup:
160 func.append(" XGL_RESULT res;")
161 func.append("")
162
163 # active layers before dispatching CreateDevice
164 if proto.name == "CreateDevice":
165 func.append(" loader_activate_layers(%s, %s);" %
166 (proto.params[0].name, proto.params[1].name))
167 func.append("")
168
169 # get dispatch table and unwrap GPUs
170 for param in proto.params:
171 stmt = ""
172 if param.ty == "XGL_PHYSICAL_GPU":
173 stmt = "loader_unwrap_gpu(&%s);" % param.name
174 if param == proto.params[0]:
175 stmt = "disp = " + stmt
176 elif param == proto.params[0]:
177 stmt = "disp = loader_get_data(%s);" % param.name
178
179 if stmt:
180 func.append(" " + stmt)
181 func.append("")
182
183 # dispatch!
184 dispatch = "disp->%s;" % proto.c_call()
185 if proto.ret == 'void':
186 func.append(" " + dispatch)
187 elif not obj_setup:
188 func.append(" return " + dispatch)
189 else:
190 func.append(" res = " + dispatch)
191 func.append(obj_setup)
192 func.append("")
193 func.append(" return res;")
194
195 func.append("}")
196
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700197 if 'WsiX11AssociateConnection' == proto.name:
Ian Elliottd1597d22015-02-26 14:34:52 -0700198 funcs.append("#if defined(__linux__) || defined(XCB_NVIDIA)")
Chia-I Wu327c3f52015-04-11 16:07:13 +0800199
200 funcs.append("\n".join(func))
Chia-I Wudac3e492014-08-02 23:49:43 +0800201
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700202 funcs.append("#endif")
Chia-I Wudac3e492014-08-02 23:49:43 +0800203 return "\n\n".join(funcs)
204
Chia-I Wufb2559d2014-08-01 11:19:52 +0800205 def generate_body(self):
Chia-I Wu2e4f5302015-01-02 00:21:24 +0800206 body = [self._generate_loader_dispatch_entrypoints("LOADER_EXPORT")]
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600207
208 return "\n\n".join(body)
209
Chia-I Wu29271d72015-01-04 10:19:50 +0800210class DispatchTableOpsSubcommand(Subcommand):
211 def run(self):
212 if len(self.argv) != 1:
213 print("DispatchTableOpsSubcommand: <prefix> unspecified")
214 return
215
216 self.prefix = self.argv[0]
217 super().run()
218
219 def generate_header(self):
220 return "\n".join(["#include <xgl.h>",
221 "#include <xglLayer.h>",
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700222 "#include <string.h>",
223 "#include \"loader_platform.h\""])
Chia-I Wu29271d72015-01-04 10:19:50 +0800224
225 def _generate_init(self):
226 stmts = []
227 for proto in self.protos:
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700228 if 'WsiX11AssociateConnection' == proto.name:
Ian Elliottd1597d22015-02-26 14:34:52 -0700229 stmts.append("#if defined(__linux__) || defined(XCB_NVIDIA)")
Chia-I Wu29271d72015-01-04 10:19:50 +0800230 if proto.name == "GetProcAddr":
231 stmts.append("table->%s = gpa; /* direct assignment */" %
232 proto.name)
233 else:
Mark Lobodzinski391bb6d2015-01-09 15:12:03 -0600234 stmts.append("table->%s = (xgl%sType) gpa(gpu, \"xgl%s\");" %
Chia-I Wu29271d72015-01-04 10:19:50 +0800235 (proto.name, proto.name, proto.name))
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700236 stmts.append("#endif")
Chia-I Wu29271d72015-01-04 10:19:50 +0800237
238 func = []
Ian Elliottfeae4052015-02-18 12:38:04 -0700239 func.append("static inline void %s_initialize_dispatch_table(XGL_LAYER_DISPATCH_TABLE *table,"
Chia-I Wu29271d72015-01-04 10:19:50 +0800240 % self.prefix)
Mark Lobodzinski391bb6d2015-01-09 15:12:03 -0600241 func.append("%s xglGetProcAddrType gpa,"
Chia-I Wu29271d72015-01-04 10:19:50 +0800242 % (" " * len(self.prefix)))
243 func.append("%s XGL_PHYSICAL_GPU gpu)"
244 % (" " * len(self.prefix)))
245 func.append("{")
246 func.append(" %s" % "\n ".join(stmts))
247 func.append("}")
248
249 return "\n".join(func)
250
251 def _generate_lookup(self):
252 lookups = []
253 for proto in self.protos:
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700254 if 'WsiX11AssociateConnection' == proto.name:
Ian Elliottd1597d22015-02-26 14:34:52 -0700255 lookups.append("#if defined(__linux__) || defined(XCB_NVIDIA)")
Chia-I Wu29271d72015-01-04 10:19:50 +0800256 lookups.append("if (!strcmp(name, \"%s\"))" % (proto.name))
257 lookups.append(" return (void *) table->%s;"
258 % (proto.name))
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700259 lookups.append("#endif")
Chia-I Wu29271d72015-01-04 10:19:50 +0800260
261 func = []
Ian Elliottfeae4052015-02-18 12:38:04 -0700262 func.append("static inline void *%s_lookup_dispatch_table(const XGL_LAYER_DISPATCH_TABLE *table,"
Chia-I Wu29271d72015-01-04 10:19:50 +0800263 % self.prefix)
264 func.append("%s const char *name)"
265 % (" " * len(self.prefix)))
266 func.append("{")
Chia-I Wu6cdaedb2015-01-05 12:55:13 +0800267 func.append(generate_get_proc_addr_check("name"))
Chia-I Wu29271d72015-01-04 10:19:50 +0800268 func.append("")
269 func.append(" name += 3;")
270 func.append(" %s" % "\n ".join(lookups))
271 func.append("")
272 func.append(" return NULL;")
273 func.append("}")
274
275 return "\n".join(func)
276
277 def generate_body(self):
278 body = [self._generate_init(),
279 self._generate_lookup()]
280
281 return "\n\n".join(body)
282
Chia-I Wueeb0ab62015-01-03 23:48:15 +0800283class IcdDummyEntrypointsSubcommand(Subcommand):
Chia-I Wudf3c4322014-08-04 10:08:08 +0800284 def run(self):
Chia-I Wueeb0ab62015-01-03 23:48:15 +0800285 if len(self.argv) == 1:
286 self.prefix = self.argv[0]
287 self.qual = "static"
288 else:
289 self.prefix = "xgl"
290 self.qual = "ICD_EXPORT"
Chia-I Wudf3c4322014-08-04 10:08:08 +0800291
292 super().run()
293
294 def generate_header(self):
295 return "#include \"icd.h\""
296
297 def _generate_stub_decl(self, proto):
Chia-I Wu595ada12015-01-04 12:05:41 +0800298 return proto.c_pretty_decl(self.prefix + proto.name, attr="XGLAPI")
Chia-I Wudf3c4322014-08-04 10:08:08 +0800299
300 def _generate_stubs(self):
301 stubs = []
302 for proto in self.protos:
Chia-I Wudf3c4322014-08-04 10:08:08 +0800303 decl = self._generate_stub_decl(proto)
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600304 if proto.ret != "void":
Chia-I Wueeb0ab62015-01-03 23:48:15 +0800305 stmt = " return XGL_ERROR_UNKNOWN;\n"
Chia-I Wudf3c4322014-08-04 10:08:08 +0800306 else:
307 stmt = ""
308
Chia-I Wueeb0ab62015-01-03 23:48:15 +0800309 stubs.append("%s %s\n{\n%s}" % (self.qual, decl, stmt))
Chia-I Wudf3c4322014-08-04 10:08:08 +0800310
311 return "\n\n".join(stubs)
312
Chia-I Wudf3c4322014-08-04 10:08:08 +0800313 def generate_body(self):
Chia-I Wueeb0ab62015-01-03 23:48:15 +0800314 return self._generate_stubs()
Chia-I Wudf3c4322014-08-04 10:08:08 +0800315
Chia-I Wu7f6d66e2015-01-04 00:11:17 +0800316class IcdGetProcAddrSubcommand(IcdDummyEntrypointsSubcommand):
317 def generate_header(self):
318 return "\n".join(["#include <string.h>", "#include \"icd.h\""])
319
320 def generate_body(self):
321 for proto in self.protos:
322 if proto.name == "GetProcAddr":
323 gpa_proto = proto
324
325 gpa_decl = self._generate_stub_decl(gpa_proto)
326 gpa_pname = gpa_proto.params[-1].name
327
328 lookups = []
329 for proto in self.protos:
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700330 if 'WsiX11AssociateConnection' == proto.name:
Ian Elliottd1597d22015-02-26 14:34:52 -0700331 lookups.append("#if defined(__linux__) || defined(XCB_NVIDIA)")
Chia-I Wu7f6d66e2015-01-04 00:11:17 +0800332 lookups.append("if (!strcmp(%s, \"%s\"))" %
333 (gpa_pname, proto.name))
334 lookups.append(" return (%s) %s%s;" %
335 (gpa_proto.ret, self.prefix, proto.name))
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700336 lookups.append("#endif")
Chia-I Wu7f6d66e2015-01-04 00:11:17 +0800337
338 body = []
339 body.append("%s %s" % (self.qual, gpa_decl))
340 body.append("{")
Chia-I Wu6cdaedb2015-01-05 12:55:13 +0800341 body.append(generate_get_proc_addr_check(gpa_pname))
Chia-I Wu7f6d66e2015-01-04 00:11:17 +0800342 body.append("")
343 body.append(" %s += 3;" % gpa_pname)
344 body.append(" %s" % "\n ".join(lookups))
345 body.append("")
346 body.append(" return NULL;")
347 body.append("}")
348
349 return "\n".join(body)
350
Chia-I Wuef9f1822015-01-05 12:56:13 +0800351class LayerInterceptProcSubcommand(Subcommand):
352 def run(self):
353 self.prefix = "xgl"
354
355 # we could get the list from argv if wanted
356 self.intercepted = [proto.name for proto in self.protos
Jon Ashburne5f98b92015-01-29 16:54:38 -0700357 if proto.name not in ["EnumerateGpus"]]
Chia-I Wuef9f1822015-01-05 12:56:13 +0800358
359 for proto in self.protos:
360 if proto.name == "GetProcAddr":
361 self.gpa = proto
362
363 super().run()
364
365 def generate_header(self):
366 return "\n".join(["#include <string.h>", "#include \"xglLayer.h\""])
367
368 def generate_body(self):
369 lookups = []
370 for proto in self.protos:
371 if proto.name not in self.intercepted:
372 lookups.append("/* no %s%s */" % (self.prefix, proto.name))
373 continue
374
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700375 if 'WsiX11AssociateConnection' == proto.name:
Ian Elliottd1597d22015-02-26 14:34:52 -0700376 lookups.append("#if defined(__linux__) || defined(XCB_NVIDIA)")
Chia-I Wuef9f1822015-01-05 12:56:13 +0800377 lookups.append("if (!strcmp(name, \"%s\"))" % proto.name)
378 lookups.append(" return (%s) %s%s;" %
379 (self.gpa.ret, self.prefix, proto.name))
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700380 lookups.append("#endif")
Chia-I Wuef9f1822015-01-05 12:56:13 +0800381
382 body = []
Ian Elliottfeae4052015-02-18 12:38:04 -0700383 body.append("static inline %s layer_intercept_proc(const char *name)" %
Chia-I Wuef9f1822015-01-05 12:56:13 +0800384 self.gpa.ret)
385 body.append("{")
386 body.append(generate_get_proc_addr_check("name"))
387 body.append("")
388 body.append(" name += 3;")
389 body.append(" %s" % "\n ".join(lookups))
390 body.append("")
391 body.append(" return NULL;")
392 body.append("}")
393
394 return "\n".join(body)
395
Chia-I Wu0a6644b2015-04-11 10:56:50 +0800396class WinDefFileSubcommand(Subcommand):
397 def run(self):
398 library_exports = {
399 "all": [],
400 "icd": [
401 "EnumerateGpus",
402 "CreateInstance",
403 "DestroyInstance",
404 "GetProcAddr",
405 ],
406 "layer": [
407 "GetProcAddr",
408 "EnumerateLayers",
409 ],
410 }
411
412 if len(self.argv) != 2 or self.argv[1] not in library_exports:
413 print("WinDefFileSubcommand: <library-name> {%s}" %
414 "|".join(library_exports.keys()))
415 return
416
417 self.library = self.argv[0]
418 self.exports = library_exports[self.argv[1]]
419
420 super().run()
421
422 def generate_copyright(self):
423 return """; THIS FILE IS GENERATED. DO NOT EDIT.
424
425;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
426; XGL
427;
428; Copyright (C) 2015 LunarG, Inc.
429;
430; Permission is hereby granted, free of charge, to any person obtaining a
431; copy of this software and associated documentation files (the "Software"),
432; to deal in the Software without restriction, including without limitation
433; the rights to use, copy, modify, merge, publish, distribute, sublicense,
434; and/or sell copies of the Software, and to permit persons to whom the
435; Software is furnished to do so, subject to the following conditions:
436;
437; The above copyright notice and this permission notice shall be included
438; in all copies or substantial portions of the Software.
439;
440; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
441; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
442; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
443; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
444; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
445; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
446; DEALINGS IN THE SOFTWARE.
447;;;; End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"""
448
449 def generate_header(self):
450 return "; The following is required on Windows, for exporting symbols from the DLL"
451
452 def generate_body(self):
453 body = []
454
455 body.append("LIBRARY " + self.library)
456 body.append("EXPORTS")
457
458 for proto in self.protos:
459 if self.exports and proto.name not in self.exports:
460 continue
461 body.append(" xgl" + proto.name)
462
463 return "\n".join(body)
464
Chia-I Wufb2559d2014-08-01 11:19:52 +0800465def main():
466 subcommands = {
Chia-I Wub3d5e192015-01-04 10:15:48 +0800467 "loader-entrypoints": LoaderEntrypointsSubcommand,
Chia-I Wu29271d72015-01-04 10:19:50 +0800468 "dispatch-table-ops": DispatchTableOpsSubcommand,
Chia-I Wueeb0ab62015-01-03 23:48:15 +0800469 "icd-dummy-entrypoints": IcdDummyEntrypointsSubcommand,
Chia-I Wu7f6d66e2015-01-04 00:11:17 +0800470 "icd-get-proc-addr": IcdGetProcAddrSubcommand,
Chia-I Wuef9f1822015-01-05 12:56:13 +0800471 "layer-intercept-proc": LayerInterceptProcSubcommand,
Chia-I Wu0a6644b2015-04-11 10:56:50 +0800472 "win-def-file": WinDefFileSubcommand,
Chia-I Wufb2559d2014-08-01 11:19:52 +0800473 }
474
475 if len(sys.argv) < 2 or sys.argv[1] not in subcommands:
476 print("Usage: %s <subcommand> [options]" % sys.argv[0])
477 print
478 print("Available sucommands are: %s" % " ".join(subcommands))
479 exit(1)
480
481 subcmd = subcommands[sys.argv[1]](sys.argv[2:])
482 subcmd.run()
483
484if __name__ == "__main__":
485 main()