1#!/usr/bin/env python3
2#
3# Copyright (c) 2015-2016 The Khronos Group Inc.
4# Copyright (c) 2015-2016 Valve Corporation
5# Copyright (c) 2015-2016 LunarG, Inc.
6# Copyright (c) 2015-2016 Google Inc.
7#
8# Permission is hereby granted, free of charge, to any person obtaining a copy
9# of this software and/or associated documentation files (the "Materials"), to
10# deal in the Materials without restriction, including without limitation the
11# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12# sell copies of the Materials, and to permit persons to whom the Materials
13# are furnished to do so, subject to the following conditions:
14#
15# The above copyright notice(s) and this permission notice shall be included
16# in all copies or substantial portions of the Materials.
17#
18# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21#
22# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
23# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
25# USE OR OTHER DEALINGS IN THE MATERIALS
26#
27# Author: Chia-I Wu <olv@lunarg.com>
28# Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
29# Author: Jon Ashburn <jon@lunarg.com>
30# Author: Gwan-gyeong Mun <kk.moon@samsung.com>
31
32import sys
33
34import vulkan
35
36def generate_get_proc_addr_check(name):
37    return "    if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \
38           "        return NULL;" % ((name,) * 3)
39
40class Subcommand(object):
41    def __init__(self, argv):
42        self.argv = argv
43        self.headers = vulkan.headers
44        self.protos = vulkan.protos
45
46    def run(self):
47        print(self.generate())
48
49    def generate(self):
50        copyright = self.generate_copyright()
51        header = self.generate_header()
52        body = self.generate_body()
53        footer = self.generate_footer()
54
55        contents = []
56        if copyright:
57            contents.append(copyright)
58        if header:
59            contents.append(header)
60        if body:
61            contents.append(body)
62        if footer:
63            contents.append(footer)
64
65        return "\n\n".join(contents)
66
67    def generate_copyright(self):
68        return """/* THIS FILE IS GENERATED.  DO NOT EDIT. */
69
70/*
71 * Copyright (c) 2015-2016 The Khronos Group Inc.
72 * Copyright (c) 2015-2016 Valve Corporation
73 * Copyright (c) 2015-2016 LunarG, Inc.
74 *
75 * Permission is hereby granted, free of charge, to any person obtaining a copy
76 * of this software and/or associated documentation files (the "Materials"), to
77 * deal in the Materials without restriction, including without limitation the
78 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
79 * sell copies of the Materials, and to permit persons to whom the Materials are
80 * furnished to do so, subject to the following conditions:
81 *
82 * The above copyright notice(s) and this permission notice shall be included in
83 * all copies or substantial portions of the Materials.
84 *
85 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
86 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
87 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
88 *
89 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
90 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
91 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
92 * USE OR OTHER DEALINGS IN THE MATERIALS.
93 *
94 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
95 */"""
96
97    def generate_header(self):
98        return "\n".join(["#include <" + h + ">" for h in self.headers])
99
100    def generate_body(self):
101        pass
102
103    def generate_footer(self):
104        pass
105
106class DispatchTableOpsSubcommand(Subcommand):
107    def run(self):
108        if len(self.argv) != 1:
109            print("DispatchTableOpsSubcommand: <prefix> unspecified")
110            return
111
112        self.prefix = self.argv[0]
113        super(DispatchTableOpsSubcommand, self).run()
114
115    def generate_header(self):
116        return "\n".join(["#include <vulkan/vulkan.h>",
117                          "#include <vulkan/vk_layer.h>",
118                          "#include <string.h>"])
119
120    def _generate_init_dispatch(self, type):
121        stmts = []
122        func = []
123        if type == "device":
124            # GPA has to be first one and uses wrapped object
125            stmts.append("memset(table, 0, sizeof(*table));")
126            stmts.append("table->GetDeviceProcAddr =(PFN_vkGetDeviceProcAddr)  gpa(device,\"vkGetDeviceProcAddr\");")
127            for proto in self.protos:
128                if proto.name == "CreateInstance" or proto.name == "EnumerateInstanceExtensionProperties" or proto.name == "EnumerateInstanceLayerProperties" or proto.params[0].ty == "VkInstance" or proto.params[0].ty == "VkPhysicalDevice":
129                    continue
130                if proto.name != "GetDeviceProcAddr" and 'KHR' not in proto.name:
131                    stmts.append("table->%s = (PFN_vk%s) gpa(device, \"vk%s\");" %
132                        (proto.name, proto.name, proto.name))
133            func.append("static inline void %s_init_device_dispatch_table(VkDevice device,"
134                % self.prefix)
135            func.append("%s                                               VkLayerDispatchTable *table,"
136                % (" " * len(self.prefix)))
137            func.append("%s                                               PFN_vkGetDeviceProcAddr gpa)"
138                % (" " * len(self.prefix)))
139        else:
140            stmts.append("table->GetInstanceProcAddr =(PFN_vkGetInstanceProcAddr)  gpa(instance,\"vkGetInstanceProcAddr\");")
141            for proto in self.protos:
142                if proto.params[0].ty != "VkInstance" and proto.params[0].ty != "VkPhysicalDevice":
143                    continue
144                if proto.name == "CreateDevice":
145                    continue
146                if proto.name != "GetInstanceProcAddr" and 'KHR' not in proto.name:
147                    stmts.append("table->%s = (PFN_vk%s) gpa(instance, \"vk%s\");" %
148                          (proto.name, proto.name, proto.name))
149            func.append("static inline void %s_init_instance_dispatch_table(" % self.prefix)
150            func.append("%s        VkInstance instance," % (" " * len(self.prefix)))
151            func.append("%s        VkLayerInstanceDispatchTable *table," % (" " * len(self.prefix)))
152            func.append("%s        PFN_vkGetInstanceProcAddr gpa)" % (" " * len(self.prefix)))
153        func.append("{")
154        func.append("    %s" % "\n    ".join(stmts))
155        func.append("}")
156
157        return "\n".join(func)
158
159    def generate_body(self):
160        body = [self._generate_init_dispatch("device"),
161                self._generate_init_dispatch("instance")]
162
163        return "\n\n".join(body)
164
165class WinDefFileSubcommand(Subcommand):
166    def run(self):
167        library_exports = {
168                "all": [],
169                "icd": [
170                    "vk_icdGetInstanceProcAddr",
171                ],
172                "layer": [
173                    "vkGetInstanceProcAddr",
174                    "vkGetDeviceProcAddr",
175                    "vkEnumerateInstanceLayerProperties",
176                    "vkEnumerateInstanceExtensionProperties"
177                ],
178                "layer_multi": [
179                    "multi2GetInstanceProcAddr",
180                    "multi1GetDeviceProcAddr"
181                ]
182        }
183
184        if len(self.argv) != 2 or self.argv[1] not in library_exports:
185            print("WinDefFileSubcommand: <library-name> {%s}" %
186                    "|".join(library_exports.keys()))
187            return
188
189        self.library = self.argv[0]
190        if self.library == "VkLayer_multi":
191            self.exports = library_exports["layer_multi"]
192        else:
193            self.exports = library_exports[self.argv[1]]
194
195        super().run()
196
197    def generate_copyright(self):
198        return """; THIS FILE IS GENERATED.  DO NOT EDIT.
199
200;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
201; Vulkan
202;
203; Copyright (c) 2015-2016 The Khronos Group Inc.
204; Copyright (c) 2015-2016 Valve Corporation
205; Copyright (c) 2015-2016 LunarG, Inc.
206;
207; Permission is hereby granted, free of charge, to any person obtaining a copy
208; of this software and/or associated documentation files (the "Materials"), to
209; deal in the Materials without restriction, including without limitation the
210; rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
211; sell copies of the Materials, and to permit persons to whom the Materials are
212; furnished to do so, subject to the following conditions:
213;
214; The above copyright notice(s) and this permission notice shall be included in
215; all copies or substantial portions of the Materials.
216;
217; THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
218; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
219; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
220;
221; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
222; DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
223; OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
224; USE OR OTHER DEALINGS IN THE MATERIALS.
225;
226;  Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
227;;;;  End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"""
228
229    def generate_header(self):
230        return "; The following is required on Windows, for exporting symbols from the DLL"
231
232    def generate_body(self):
233        body = []
234
235        body.append("LIBRARY " + self.library)
236        body.append("EXPORTS")
237
238        for proto in self.exports:
239            if self.library != "VkLayerSwapchain" or proto != "vkEnumerateInstanceExtensionProperties" and proto != "vkEnumerateInstanceLayerProperties":
240                body.append( proto)
241
242        return "\n".join(body)
243
244def main():
245    wsi = {
246            "Win32",
247            "Android",
248            "Xcb",
249            "Xlib",
250            "Wayland",
251            "Mir"
252    }
253    subcommands = {
254            "dispatch-table-ops": DispatchTableOpsSubcommand,
255            "win-def-file": WinDefFileSubcommand,
256    }
257
258    if len(sys.argv) < 3 or sys.argv[1] not in wsi or sys.argv[2] not in subcommands:
259        print("Usage: %s <wsi> <subcommand> [options]" % sys.argv[0])
260        print
261        print("Available sucommands are: %s" % " ".join(subcommands))
262        exit(1)
263
264    subcmd = subcommands[sys.argv[2]](sys.argv[3:])
265    subcmd.run()
266
267if __name__ == "__main__":
268    main()
269