blob: 1be98982105e908869d48d074b99e6865ccae74d [file] [log] [blame]
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -06001#!/usr/bin/env python3
2#
Jon Ashburn23d36b12016-02-02 17:47:28 -07003# Copyright (c) 2015-2016 The Khronos Group Inc.
4# Copyright (c) 2015-2016 Valve Corporation
5# Copyright (c) 2015-2016 LunarG, Inc.
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -06006#
Jon Ashburn3ebf1252016-04-19 11:30:31 -06007# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060010#
Jon Ashburn3ebf1252016-04-19 11:30:31 -060011# http://www.apache.org/licenses/LICENSE-2.0
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060012#
Jon Ashburn3ebf1252016-04-19 11:30:31 -060013# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060018#
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060019# Author: Jon Ashburn <jon@lunarg.com>
20#
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060021
22import os, sys
23
24# add main repo directory so vulkan.py can be imported. This needs to be a complete path.
25ld_path = os.path.dirname(os.path.abspath(__file__))
26main_path = os.path.abspath(ld_path + "/../")
27sys.path.append(main_path)
28
29import vulkan
30
31def generate_get_proc_addr_check(name):
32 return " if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \
33 " return NULL;" % ((name,) * 3)
34
35class Subcommand(object):
36 def __init__(self, argv):
37 self.argv = argv
38 self.headers = vulkan.headers
39 self.protos = vulkan.protos
40
41 def run(self):
42 print(self.generate())
43
Jon Ashburn82974f42015-05-05 09:37:01 -060044 def _requires_special_trampoline_code(self, name):
Eric Engestromeae5ee42016-04-02 22:06:24 +010045 # Don't be cute trying to use a general rule to programmatically populate this list
Jon Ashburn82974f42015-05-05 09:37:01 -060046 # it just obsfucates what is going on!
Ian Elliott7e40db92015-08-21 15:09:33 -060047 wsi_creates_dispatchable_object = ["CreateSwapchainKHR"]
Chia-I Wu3432a0c2015-10-27 18:04:07 +080048 creates_dispatchable_object = ["CreateDevice", "GetDeviceQueue", "AllocateCommandBuffers"] + wsi_creates_dispatchable_object
Jon Ashburn82974f42015-05-05 09:37:01 -060049 if name in creates_dispatchable_object:
50 return True
51 else:
52 return False
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060053
Jon Ashburn82974f42015-05-05 09:37:01 -060054 def _is_loader_non_trampoline_entrypoint(self, proto):
Jon Ashburn8d1b0b52015-05-18 13:20:15 -060055 if proto.name in ["GetDeviceProcAddr", "EnumeratePhysicalDevices", "EnumerateLayers", "DbgRegisterMsgCallback", "DbgUnregisterMsgCallback", "DbgSetGlobalOption", "DestroyInstance"]:
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060056 return True
57 return not self.is_dispatchable_object_first_param(proto)
58
59
60 def is_dispatchable_object_first_param(self, proto):
61 in_objs = proto.object_in_params()
62 non_dispatch_objs = []
63 param0 = proto.params[0]
64 return (len(in_objs) > 0) and (in_objs[0].ty == param0.ty) and (param0.ty not in non_dispatch_objs)
65
66 def generate(self):
67 copyright = self.generate_copyright()
68 header = self.generate_header()
69 body = self.generate_body()
70 footer = self.generate_footer()
71
72 contents = []
73 if copyright:
74 contents.append(copyright)
75 if header:
76 contents.append(header)
77 if body:
78 contents.append(body)
79 if footer:
80 contents.append(footer)
81
82 return "\n\n".join(contents)
83
84 def generate_copyright(self):
85 return """/* THIS FILE IS GENERATED. DO NOT EDIT. */
86
87/*
Jon Ashburn23d36b12016-02-02 17:47:28 -070088 * Copyright (c) 2015-2016 The Khronos Group Inc.
89 * Copyright (c) 2015-2016 Valve Corporation
90 * Copyright (c) 2015-2016 LunarG, Inc.
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060091 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060092 * Licensed under the Apache License, Version 2.0 (the "License");
93 * you may not use this file except in compliance with the License.
94 * You may obtain a copy of the License at
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060095 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060096 * http://www.apache.org/licenses/LICENSE-2.0
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -060097 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060098 * Unless required by applicable law or agreed to in writing, software
99 * distributed under the License is distributed on an "AS IS" BASIS,
100 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
101 * See the License for the specific language governing permissions and
102 * limitations under the License.
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -0600103 *
104 * Author: Jon Ashburn <jon@lunarg.com>
Jon Ashburnfc1031e2015-11-17 15:31:02 -0700105 * Author: Chia-I Wu <olv@lunarg.com>
106 * Author: Courtney Goeltzenleuchter <courtney@lunarg.com>
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600107 */"""
108
109 def generate_header(self):
110 return "\n".join(["#include <" + h + ">" for h in self.headers])
111
112 def generate_body(self):
113 pass
114
115 def generate_footer(self):
116 pass
117
Jon Ashburnfc1031e2015-11-17 15:31:02 -0700118class DevExtTrampolineSubcommand(Subcommand):
119 def generate_header(self):
120 lines = []
121 lines.append("#include \"vk_loader_platform.h\"")
122 lines.append("#include \"loader.h\"")
123 lines.append("#if defined(__linux__)")
124 lines.append("#pragma GCC optimize(3) // force gcc to use tail-calls")
125 lines.append("#endif")
126 return "\n".join(lines)
127
128 def generate_body(self):
129 lines = []
130 for i in range(250):
131 lines.append('\nVKAPI_ATTR void VKAPI_CALL vkDevExt%s(VkDevice device)' % i)
132 lines.append('{')
133 lines.append(' const struct loader_dev_dispatch_table *disp;')
134 lines.append(' disp = loader_get_dev_dispatch(device);')
135 lines.append(' disp->ext_dispatch.DevExt[%s](device);' % i)
136 lines.append('}')
137 lines.append('')
138 lines.append('void *loader_get_dev_ext_trampoline(uint32_t index)')
139 lines.append('{')
140 lines.append(' switch (index) {')
141 for i in range(250):
142 lines.append(' case %s:' % i)
143 lines.append(' return vkDevExt%s;' % i)
144 lines.append(' }')
145 lines.append(' return NULL;')
146 lines.append('}')
147 return "\n".join(lines)
148
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600149class LoaderEntrypointsSubcommand(Subcommand):
150 def generate_header(self):
151 return "#include \"loader.h\""
152
153 def _generate_object_setup(self, proto):
154 method = "loader_init_dispatch"
155 cond = "res == VK_SUCCESS"
Jon Ashburn82974f42015-05-05 09:37:01 -0600156 setup = []
157
158 if not self._requires_special_trampoline_code(proto.name):
159 return setup
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600160
161 if "Get" in proto.name:
162 method = "loader_set_dispatch"
163
Ian Elliott7e40db92015-08-21 15:09:33 -0600164 if proto.name == "GetSwapchainInfoKHR":
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600165 ptype = proto.params[-3].name
166 psize = proto.params[-2].name
167 pdata = proto.params[-1].name
Ian Elliott7e40db92015-08-21 15:09:33 -0600168 cond = ("%s == VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR && "
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600169 "%s && %s" % (ptype, pdata, cond))
Ian Elliott7e40db92015-08-21 15:09:33 -0600170 setup.append("VkSwapchainImageInfoKHR *info = %s;" % pdata)
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600171 setup.append("size_t count = *%s / sizeof(*info), i;" % psize)
172 setup.append("for (i = 0; i < count; i++) {")
173 setup.append(" %s(info[i].image, disp);" % method)
174 setup.append(" %s(info[i].memory, disp);" % method)
175 setup.append("}")
Jon Ashburn82974f42015-05-05 09:37:01 -0600176 else:
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600177 obj_params = proto.object_out_params()
178 for param in obj_params:
179 setup.append("%s(*%s, disp);" % (method, param.name))
180
181 if setup:
182 joined = "\n ".join(setup)
183 setup = []
184 setup.append(" if (%s) {" % cond)
185 setup.append(" " + joined)
186 setup.append(" }")
187
188 return "\n".join(setup)
189
190 def _generate_loader_dispatch_entrypoints(self, qual=""):
191 if qual:
192 qual += " "
193
194 funcs = []
195 for proto in self.protos:
Jon Ashburn82974f42015-05-05 09:37:01 -0600196 if self._is_loader_non_trampoline_entrypoint(proto):
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600197 continue
198 func = []
199
200 obj_setup = self._generate_object_setup(proto)
201
202 func.append(qual + proto.c_func(prefix="vk", attr="VKAPI"))
203 func.append("{")
204
205 # declare local variables
206 func.append(" const VkLayerDispatchTable *disp;")
207 if proto.ret != 'void' and obj_setup:
208 func.append(" VkResult res;")
209 func.append("")
210
211 # get dispatch table
212 func.append(" disp = loader_get_dispatch(%s);" %
213 proto.params[0].name)
214 func.append("")
215
216 # dispatch!
217 dispatch = "disp->%s;" % proto.c_call()
218 if proto.ret == 'void':
219 func.append(" " + dispatch)
220 elif not obj_setup:
221 func.append(" return " + dispatch)
222 else:
223 func.append(" res = " + dispatch)
224 func.append(obj_setup)
225 func.append("")
226 func.append(" return res;")
227
228 func.append("}")
229
230 funcs.append("\n".join(func))
231
232 return "\n\n".join(funcs)
233
234 def generate_body(self):
235 body = [self._generate_loader_dispatch_entrypoints("LOADER_EXPORT")]
236
237 return "\n\n".join(body)
238
239class DispatchTableOpsSubcommand(Subcommand):
240 def run(self):
241 if len(self.argv) != 1:
242 print("DispatchTableOpsSubcommand: <prefix> unspecified")
243 return
244
245 self.prefix = self.argv[0]
246 super().run()
247
248 def generate_header(self):
David Pinedo9316d3b2015-11-06 12:54:48 -0700249 return "\n".join(["#include <vulkan/vulkan.h>",
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600250 "#include <vkLayer.h>",
251 "#include <string.h>",
252 "#include \"loader_platform.h\""])
253
Jon Ashburnfbb4e252015-05-04 16:27:53 -0600254 def _generate_init(self, type):
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600255 stmts = []
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600256 func = []
Jon Ashburnfbb4e252015-05-04 16:27:53 -0600257 if type == "device":
258 for proto in self.protos:
259 if self.is_dispatchable_object_first_param(proto) or proto.name == "CreateInstance":
260 stmts.append("table->%s = (PFN_vk%s) gpa(gpu, \"vk%s\");" %
261 (proto.name, proto.name, proto.name))
262 else:
263 stmts.append("table->%s = vk%s; /* non-dispatchable */" %
264 (proto.name, proto.name))
265 func.append("static inline void %s_init_device_dispatch_table(VkLayerDispatchTable *table,"
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600266 % self.prefix)
Jon Ashburn8d1b0b52015-05-18 13:20:15 -0600267 func.append("%s PFN_vkGetDeviceProcAddr gpa,"
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600268 % (" " * len(self.prefix)))
Jon Ashburnfbb4e252015-05-04 16:27:53 -0600269 func.append("%s VkPhysicalDevice gpu)"
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600270 % (" " * len(self.prefix)))
Jon Ashburnfbb4e252015-05-04 16:27:53 -0600271 else:
272 for proto in self.protos:
273 if proto.params[0].ty != "VkInstance" and proto.params[0].ty != "VkPhysicalDevice":
274 continue
275 stmts.append("table->%s = vk%s;" % (proto.name, proto.name))
276 func.append("static inline void %s_init_instance_dispatch_table(VkLayerInstanceDispatchTable *table)"
277 % self.prefix)
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600278 func.append("{")
279 func.append(" %s" % "\n ".join(stmts))
280 func.append("}")
281
282 return "\n".join(func)
283
284 def _generate_lookup(self):
285 lookups = []
286 for proto in self.protos:
287 if self.is_dispatchable_object_first_param(proto):
288 lookups.append("if (!strcmp(name, \"%s\"))" % (proto.name))
289 lookups.append(" return (void *) table->%s;"
290 % (proto.name))
291
292 func = []
293 func.append("static inline void *%s_lookup_dispatch_table(const VkLayerDispatchTable *table,"
294 % self.prefix)
295 func.append("%s const char *name)"
296 % (" " * len(self.prefix)))
297 func.append("{")
298 func.append(generate_get_proc_addr_check("name"))
299 func.append("")
300 func.append(" name += 2;")
301 func.append(" %s" % "\n ".join(lookups))
302 func.append("")
303 func.append(" return NULL;")
304 func.append("}")
305
306 return "\n".join(func)
307
308 def generate_body(self):
Jon Ashburnfbb4e252015-05-04 16:27:53 -0600309 body = [self._generate_init("device"),
310 self._generate_lookup(),
311 self._generate_init("instance")]
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600312
313 return "\n\n".join(body)
314
315class WinDefFileSubcommand(Subcommand):
316 def run(self):
317 library_exports = {
318 "all": [],
319 }
320
321 if len(self.argv) != 2 or self.argv[1] not in library_exports:
322 print("WinDefFileSubcommand: <library-name> {%s}" %
323 "|".join(library_exports.keys()))
324 return
325
326 self.library = self.argv[0]
327 self.exports = library_exports[self.argv[1]]
328
329 super().run()
330
331 def generate_copyright(self):
332 return """; THIS FILE IS GENERATED. DO NOT EDIT.
333
334;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Jon Ashburn23d36b12016-02-02 17:47:28 -0700335; Copyright (c) 2015-2016 The Khronos Group Inc.
336; Copyright (c) 2015-2016 Valve Corporation
337; Copyright (c) 2015-2016 LunarG, Inc.
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600338;
Jon Ashburn3ebf1252016-04-19 11:30:31 -0600339; Licensed under the Apache License, Version 2.0 (the "License");
340; you may not use this file except in compliance with the License.
341; You may obtain a copy of the License at
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600342;
Jon Ashburn3ebf1252016-04-19 11:30:31 -0600343; http://www.apache.org/licenses/LICENSE-2.0
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600344;
Jon Ashburn3ebf1252016-04-19 11:30:31 -0600345; Unless required by applicable law or agreed to in writing, software
346; distributed under the License is distributed on an "AS IS" BASIS,
347; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
348; See the License for the specific language governing permissions and
349; limitations under the License.
Jon Ashburn23d36b12016-02-02 17:47:28 -0700350;
Courtney Goeltzenleuchterbdde0b22015-12-16 14:57:27 -0700351;
352; Author: Jon Ashburn <jon@lunarg.com>
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600353;;;; End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"""
354
355 def generate_header(self):
356 return "; The following is required on Windows, for exporting symbols from the DLL"
357
358 def generate_body(self):
359 body = []
360
361 body.append("LIBRARY " + self.library)
362 body.append("EXPORTS")
363
364 for proto in self.protos:
365 if self.exports and proto.name not in self.exports:
366 continue
Mark Lobodzinski3077be02015-11-24 14:03:18 -0700367# This was intended to reject WSI calls, but actually rejects ALL extensions
368# TODO: Make this WSI-extension specific
369# if proto.name.endswith("KHR"):
370# continue
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600371 body.append(" vk" + proto.name)
372
373 return "\n".join(body)
374
375class LoaderGetProcAddrSubcommand(Subcommand):
376 def run(self):
377 self.prefix = "vk"
378
379 # we could get the list from argv if wanted
380 self.intercepted = [proto.name for proto in self.protos]
381
382 for proto in self.protos:
Jon Ashburn8d1b0b52015-05-18 13:20:15 -0600383 if proto.name == "GetDeviceProcAddr":
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600384 self.gpa = proto
385
386 super().run()
387
388 def generate_header(self):
389 return "\n".join(["#include <string.h>"])
390
391 def generate_body(self):
392 lookups = []
393 for proto in self.protos:
394 if proto.name not in self.intercepted:
395 lookups.append("/* no %s%s */" % (self.prefix, proto.name))
396 continue
397
398 lookups.append("if (!strcmp(name, \"%s\"))" % proto.name)
399 lookups.append(" return (%s) %s%s;" %
400 (self.gpa.ret, self.prefix, proto.name))
401
402 special_lookups = []
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600403 for proto in self.protos:
Jon Ashburn82974f42015-05-05 09:37:01 -0600404 if self._is_loader_non_trampoline_entrypoint(proto) or self._requires_special_trampoline_code(proto.name):
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600405 special_lookups.append("if (!strcmp(name, \"%s\"))" % proto.name)
406 special_lookups.append(" return (%s) %s%s;" %
407 (self.gpa.ret, self.prefix, proto.name))
408 else:
409 continue
410 body = []
411 body.append("static inline %s globalGetProcAddr(const char *name)" %
412 self.gpa.ret)
413 body.append("{")
414 body.append(generate_get_proc_addr_check("name"))
415 body.append("")
416 body.append(" name += 2;")
417 body.append(" %s" % "\n ".join(lookups))
418 body.append("")
419 body.append(" return NULL;")
420 body.append("}")
421 body.append("")
422 body.append("static inline void *loader_non_passthrough_gpa(const char *name)")
423 body.append("{")
424 body.append(generate_get_proc_addr_check("name"))
425 body.append("")
426 body.append(" name += 2;")
427 body.append(" %s" % "\n ".join(special_lookups))
428 body.append("")
429 body.append(" return NULL;")
430 body.append("}")
431
432 return "\n".join(body)
433
434def main():
Mark Lobodzinski59816c72016-02-24 15:04:11 -0700435
436 wsi = {
437 "Win32",
438 "Android",
439 "Xcb",
440 "Xlib",
441 "Wayland",
442 "Mir"
443 }
444
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600445 subcommands = {
Jon Ashburnfc1031e2015-11-17 15:31:02 -0700446 "dev-ext-trampoline": DevExtTrampolineSubcommand,
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600447 "loader-entrypoints": LoaderEntrypointsSubcommand,
448 "dispatch-table-ops": DispatchTableOpsSubcommand,
449 "win-def-file": WinDefFileSubcommand,
450 "loader-get-proc-addr": LoaderGetProcAddrSubcommand,
451 }
452
Mark Lobodzinski59816c72016-02-24 15:04:11 -0700453 if len(sys.argv) < 3 or sys.argv[1] not in wsi or sys.argv[2] not in subcommands:
454 print("Usage: %s <wsi> <subcommand> [options]" % sys.argv[0])
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600455 print
Mark Lobodzinski59816c72016-02-24 15:04:11 -0700456 print("Available wsi (displayservers) are: %s" % " ".join(wsi))
457 print("Available subcommands are: %s" % " ".join(subcommands))
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600458 exit(1)
459
Mark Lobodzinski59816c72016-02-24 15:04:11 -0700460 subcmd = subcommands[sys.argv[2]](sys.argv[3:])
Jon Ashburn1dd0a5c2015-05-04 09:16:41 -0600461 subcmd.run()
462
463if __name__ == "__main__":
464 main()