1#!/usr/bin/env python3
2#
3# Copyright (C) 2016 Google, Inc.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the "Software"),
7# to deal in the Software without restriction, including without limitation
8# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9# and/or sell copies of the Software, and to permit persons to whom the
10# Software is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included
13# in all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21# DEALINGS IN THE SOFTWARE.
22
23"""Generate Vulkan dispatch table.
24"""
25
26import os
27import sys
28
29class Command(object):
30    PLATFORM = 0
31    LOADER = 1
32    INSTANCE = 2
33    DEVICE = 3
34
35    def __init__(self, name, dispatch):
36        self.name = name
37        self.dispatch = dispatch
38        self.ty = self._get_type()
39
40    @staticmethod
41    def valid_c_typedef(c):
42        return (c.startswith("typedef") and
43                c.endswith(");") and
44                "*PFN_vkVoidFunction" not in c)
45
46    @classmethod
47    def from_c_typedef(cls, c):
48        name_begin = c.find("*PFN_vk") + 7
49        name_end = c.find(")(", name_begin)
50        name = c[name_begin:name_end]
51
52        dispatch_begin = name_end + 2
53        dispatch_end = c.find(" ", dispatch_begin)
54        dispatch = c[dispatch_begin:dispatch_end]
55        if not dispatch.startswith("Vk"):
56            dispatch = None
57
58        return cls(name, dispatch)
59
60    def _get_type(self):
61        if self.dispatch:
62            if self.dispatch in ["VkDevice", "VkQueue", "VkCommandBuffer"]:
63                return self.DEVICE
64            else:
65                return self.INSTANCE
66        else:
67            if self.name in ["GetInstanceProcAddr"]:
68                return self.PLATFORM
69            else:
70                return self.LOADER
71
72    def __repr__(self):
73        return "Command(name=%s, dispatch=%s)" % \
74                (repr(self.name), repr(self.dispatch))
75
76class Extension(object):
77    def __init__(self, name, version, guard=None, commands=[]):
78        self.name = name
79        self.version = version
80        self.guard = guard
81        self.commands = commands[:]
82
83    def add_command(self, cmd):
84        self.commands.append(cmd)
85
86    def __repr__(self):
87        lines = []
88        lines.append("Extension(name=%s, version=%s, guard=%s, commands=[" %
89                (repr(self.name), repr(self.version), repr(self.guard)))
90
91        for cmd in self.commands:
92            lines.append("    %s," % repr(cmd))
93
94        lines.append("])")
95
96        return "\n".join(lines)
97
98# generated by "generate-dispatch-table parse vulkan.h"
99vk_core = Extension(name='VK_core', version=0, guard=None, commands=[
100    Command(name='CreateInstance', dispatch=None),
101    Command(name='DestroyInstance', dispatch='VkInstance'),
102    Command(name='EnumeratePhysicalDevices', dispatch='VkInstance'),
103    Command(name='GetPhysicalDeviceFeatures', dispatch='VkPhysicalDevice'),
104    Command(name='GetPhysicalDeviceFormatProperties', dispatch='VkPhysicalDevice'),
105    Command(name='GetPhysicalDeviceImageFormatProperties', dispatch='VkPhysicalDevice'),
106    Command(name='GetPhysicalDeviceProperties', dispatch='VkPhysicalDevice'),
107    Command(name='GetPhysicalDeviceQueueFamilyProperties', dispatch='VkPhysicalDevice'),
108    Command(name='GetPhysicalDeviceMemoryProperties', dispatch='VkPhysicalDevice'),
109    Command(name='GetInstanceProcAddr', dispatch='VkInstance'),
110    Command(name='GetDeviceProcAddr', dispatch='VkDevice'),
111    Command(name='CreateDevice', dispatch='VkPhysicalDevice'),
112    Command(name='DestroyDevice', dispatch='VkDevice'),
113    Command(name='EnumerateInstanceExtensionProperties', dispatch=None),
114    Command(name='EnumerateDeviceExtensionProperties', dispatch='VkPhysicalDevice'),
115    Command(name='EnumerateInstanceLayerProperties', dispatch=None),
116    Command(name='EnumerateDeviceLayerProperties', dispatch='VkPhysicalDevice'),
117    Command(name='GetDeviceQueue', dispatch='VkDevice'),
118    Command(name='QueueSubmit', dispatch='VkQueue'),
119    Command(name='QueueWaitIdle', dispatch='VkQueue'),
120    Command(name='DeviceWaitIdle', dispatch='VkDevice'),
121    Command(name='AllocateMemory', dispatch='VkDevice'),
122    Command(name='FreeMemory', dispatch='VkDevice'),
123    Command(name='MapMemory', dispatch='VkDevice'),
124    Command(name='UnmapMemory', dispatch='VkDevice'),
125    Command(name='FlushMappedMemoryRanges', dispatch='VkDevice'),
126    Command(name='InvalidateMappedMemoryRanges', dispatch='VkDevice'),
127    Command(name='GetDeviceMemoryCommitment', dispatch='VkDevice'),
128    Command(name='BindBufferMemory', dispatch='VkDevice'),
129    Command(name='BindImageMemory', dispatch='VkDevice'),
130    Command(name='GetBufferMemoryRequirements', dispatch='VkDevice'),
131    Command(name='GetImageMemoryRequirements', dispatch='VkDevice'),
132    Command(name='GetImageSparseMemoryRequirements', dispatch='VkDevice'),
133    Command(name='GetPhysicalDeviceSparseImageFormatProperties', dispatch='VkPhysicalDevice'),
134    Command(name='QueueBindSparse', dispatch='VkQueue'),
135    Command(name='CreateFence', dispatch='VkDevice'),
136    Command(name='DestroyFence', dispatch='VkDevice'),
137    Command(name='ResetFences', dispatch='VkDevice'),
138    Command(name='GetFenceStatus', dispatch='VkDevice'),
139    Command(name='WaitForFences', dispatch='VkDevice'),
140    Command(name='CreateSemaphore', dispatch='VkDevice'),
141    Command(name='DestroySemaphore', dispatch='VkDevice'),
142    Command(name='CreateEvent', dispatch='VkDevice'),
143    Command(name='DestroyEvent', dispatch='VkDevice'),
144    Command(name='GetEventStatus', dispatch='VkDevice'),
145    Command(name='SetEvent', dispatch='VkDevice'),
146    Command(name='ResetEvent', dispatch='VkDevice'),
147    Command(name='CreateQueryPool', dispatch='VkDevice'),
148    Command(name='DestroyQueryPool', dispatch='VkDevice'),
149    Command(name='GetQueryPoolResults', dispatch='VkDevice'),
150    Command(name='CreateBuffer', dispatch='VkDevice'),
151    Command(name='DestroyBuffer', dispatch='VkDevice'),
152    Command(name='CreateBufferView', dispatch='VkDevice'),
153    Command(name='DestroyBufferView', dispatch='VkDevice'),
154    Command(name='CreateImage', dispatch='VkDevice'),
155    Command(name='DestroyImage', dispatch='VkDevice'),
156    Command(name='GetImageSubresourceLayout', dispatch='VkDevice'),
157    Command(name='CreateImageView', dispatch='VkDevice'),
158    Command(name='DestroyImageView', dispatch='VkDevice'),
159    Command(name='CreateShaderModule', dispatch='VkDevice'),
160    Command(name='DestroyShaderModule', dispatch='VkDevice'),
161    Command(name='CreatePipelineCache', dispatch='VkDevice'),
162    Command(name='DestroyPipelineCache', dispatch='VkDevice'),
163    Command(name='GetPipelineCacheData', dispatch='VkDevice'),
164    Command(name='MergePipelineCaches', dispatch='VkDevice'),
165    Command(name='CreateGraphicsPipelines', dispatch='VkDevice'),
166    Command(name='CreateComputePipelines', dispatch='VkDevice'),
167    Command(name='DestroyPipeline', dispatch='VkDevice'),
168    Command(name='CreatePipelineLayout', dispatch='VkDevice'),
169    Command(name='DestroyPipelineLayout', dispatch='VkDevice'),
170    Command(name='CreateSampler', dispatch='VkDevice'),
171    Command(name='DestroySampler', dispatch='VkDevice'),
172    Command(name='CreateDescriptorSetLayout', dispatch='VkDevice'),
173    Command(name='DestroyDescriptorSetLayout', dispatch='VkDevice'),
174    Command(name='CreateDescriptorPool', dispatch='VkDevice'),
175    Command(name='DestroyDescriptorPool', dispatch='VkDevice'),
176    Command(name='ResetDescriptorPool', dispatch='VkDevice'),
177    Command(name='AllocateDescriptorSets', dispatch='VkDevice'),
178    Command(name='FreeDescriptorSets', dispatch='VkDevice'),
179    Command(name='UpdateDescriptorSets', dispatch='VkDevice'),
180    Command(name='CreateFramebuffer', dispatch='VkDevice'),
181    Command(name='DestroyFramebuffer', dispatch='VkDevice'),
182    Command(name='CreateRenderPass', dispatch='VkDevice'),
183    Command(name='DestroyRenderPass', dispatch='VkDevice'),
184    Command(name='GetRenderAreaGranularity', dispatch='VkDevice'),
185    Command(name='CreateCommandPool', dispatch='VkDevice'),
186    Command(name='DestroyCommandPool', dispatch='VkDevice'),
187    Command(name='ResetCommandPool', dispatch='VkDevice'),
188    Command(name='AllocateCommandBuffers', dispatch='VkDevice'),
189    Command(name='FreeCommandBuffers', dispatch='VkDevice'),
190    Command(name='BeginCommandBuffer', dispatch='VkCommandBuffer'),
191    Command(name='EndCommandBuffer', dispatch='VkCommandBuffer'),
192    Command(name='ResetCommandBuffer', dispatch='VkCommandBuffer'),
193    Command(name='CmdBindPipeline', dispatch='VkCommandBuffer'),
194    Command(name='CmdSetViewport', dispatch='VkCommandBuffer'),
195    Command(name='CmdSetScissor', dispatch='VkCommandBuffer'),
196    Command(name='CmdSetLineWidth', dispatch='VkCommandBuffer'),
197    Command(name='CmdSetDepthBias', dispatch='VkCommandBuffer'),
198    Command(name='CmdSetBlendConstants', dispatch='VkCommandBuffer'),
199    Command(name='CmdSetDepthBounds', dispatch='VkCommandBuffer'),
200    Command(name='CmdSetStencilCompareMask', dispatch='VkCommandBuffer'),
201    Command(name='CmdSetStencilWriteMask', dispatch='VkCommandBuffer'),
202    Command(name='CmdSetStencilReference', dispatch='VkCommandBuffer'),
203    Command(name='CmdBindDescriptorSets', dispatch='VkCommandBuffer'),
204    Command(name='CmdBindIndexBuffer', dispatch='VkCommandBuffer'),
205    Command(name='CmdBindVertexBuffers', dispatch='VkCommandBuffer'),
206    Command(name='CmdDraw', dispatch='VkCommandBuffer'),
207    Command(name='CmdDrawIndexed', dispatch='VkCommandBuffer'),
208    Command(name='CmdDrawIndirect', dispatch='VkCommandBuffer'),
209    Command(name='CmdDrawIndexedIndirect', dispatch='VkCommandBuffer'),
210    Command(name='CmdDispatch', dispatch='VkCommandBuffer'),
211    Command(name='CmdDispatchIndirect', dispatch='VkCommandBuffer'),
212    Command(name='CmdCopyBuffer', dispatch='VkCommandBuffer'),
213    Command(name='CmdCopyImage', dispatch='VkCommandBuffer'),
214    Command(name='CmdBlitImage', dispatch='VkCommandBuffer'),
215    Command(name='CmdCopyBufferToImage', dispatch='VkCommandBuffer'),
216    Command(name='CmdCopyImageToBuffer', dispatch='VkCommandBuffer'),
217    Command(name='CmdUpdateBuffer', dispatch='VkCommandBuffer'),
218    Command(name='CmdFillBuffer', dispatch='VkCommandBuffer'),
219    Command(name='CmdClearColorImage', dispatch='VkCommandBuffer'),
220    Command(name='CmdClearDepthStencilImage', dispatch='VkCommandBuffer'),
221    Command(name='CmdClearAttachments', dispatch='VkCommandBuffer'),
222    Command(name='CmdResolveImage', dispatch='VkCommandBuffer'),
223    Command(name='CmdSetEvent', dispatch='VkCommandBuffer'),
224    Command(name='CmdResetEvent', dispatch='VkCommandBuffer'),
225    Command(name='CmdWaitEvents', dispatch='VkCommandBuffer'),
226    Command(name='CmdPipelineBarrier', dispatch='VkCommandBuffer'),
227    Command(name='CmdBeginQuery', dispatch='VkCommandBuffer'),
228    Command(name='CmdEndQuery', dispatch='VkCommandBuffer'),
229    Command(name='CmdResetQueryPool', dispatch='VkCommandBuffer'),
230    Command(name='CmdWriteTimestamp', dispatch='VkCommandBuffer'),
231    Command(name='CmdCopyQueryPoolResults', dispatch='VkCommandBuffer'),
232    Command(name='CmdPushConstants', dispatch='VkCommandBuffer'),
233    Command(name='CmdBeginRenderPass', dispatch='VkCommandBuffer'),
234    Command(name='CmdNextSubpass', dispatch='VkCommandBuffer'),
235    Command(name='CmdEndRenderPass', dispatch='VkCommandBuffer'),
236    Command(name='CmdExecuteCommands', dispatch='VkCommandBuffer'),
237])
238
239vk_khr_surface = Extension(name='VK_KHR_surface', version=25, guard=None, commands=[
240    Command(name='DestroySurfaceKHR', dispatch='VkInstance'),
241    Command(name='GetPhysicalDeviceSurfaceSupportKHR', dispatch='VkPhysicalDevice'),
242    Command(name='GetPhysicalDeviceSurfaceCapabilitiesKHR', dispatch='VkPhysicalDevice'),
243    Command(name='GetPhysicalDeviceSurfaceFormatsKHR', dispatch='VkPhysicalDevice'),
244    Command(name='GetPhysicalDeviceSurfacePresentModesKHR', dispatch='VkPhysicalDevice'),
245])
246
247vk_khr_swapchain = Extension(name='VK_KHR_swapchain', version=67, guard=None, commands=[
248    Command(name='CreateSwapchainKHR', dispatch='VkDevice'),
249    Command(name='DestroySwapchainKHR', dispatch='VkDevice'),
250    Command(name='GetSwapchainImagesKHR', dispatch='VkDevice'),
251    Command(name='AcquireNextImageKHR', dispatch='VkDevice'),
252    Command(name='QueuePresentKHR', dispatch='VkQueue'),
253])
254
255vk_khr_display = Extension(name='VK_KHR_display', version=21, guard=None, commands=[
256    Command(name='GetPhysicalDeviceDisplayPropertiesKHR', dispatch='VkPhysicalDevice'),
257    Command(name='GetPhysicalDeviceDisplayPlanePropertiesKHR', dispatch='VkPhysicalDevice'),
258    Command(name='GetDisplayPlaneSupportedDisplaysKHR', dispatch='VkPhysicalDevice'),
259    Command(name='GetDisplayModePropertiesKHR', dispatch='VkPhysicalDevice'),
260    Command(name='CreateDisplayModeKHR', dispatch='VkPhysicalDevice'),
261    Command(name='GetDisplayPlaneCapabilitiesKHR', dispatch='VkPhysicalDevice'),
262    Command(name='CreateDisplayPlaneSurfaceKHR', dispatch='VkInstance'),
263])
264
265vk_khr_display_swapchain = Extension(name='VK_KHR_display_swapchain', version=9, guard=None, commands=[
266    Command(name='CreateSharedSwapchainsKHR', dispatch='VkDevice'),
267])
268
269vk_khr_xlib_surface = Extension(name='VK_KHR_xlib_surface', version=6, guard='VK_USE_PLATFORM_XLIB_KHR', commands=[
270    Command(name='CreateXlibSurfaceKHR', dispatch='VkInstance'),
271    Command(name='GetPhysicalDeviceXlibPresentationSupportKHR', dispatch='VkPhysicalDevice'),
272])
273
274vk_khr_xcb_surface = Extension(name='VK_KHR_xcb_surface', version=6, guard='VK_USE_PLATFORM_XCB_KHR', commands=[
275    Command(name='CreateXcbSurfaceKHR', dispatch='VkInstance'),
276    Command(name='GetPhysicalDeviceXcbPresentationSupportKHR', dispatch='VkPhysicalDevice'),
277])
278
279vk_khr_wayland_surface = Extension(name='VK_KHR_wayland_surface', version=5, guard='VK_USE_PLATFORM_WAYLAND_KHR', commands=[
280    Command(name='CreateWaylandSurfaceKHR', dispatch='VkInstance'),
281    Command(name='GetPhysicalDeviceWaylandPresentationSupportKHR', dispatch='VkPhysicalDevice'),
282])
283
284vk_khr_mir_surface = Extension(name='VK_KHR_mir_surface', version=4, guard='VK_USE_PLATFORM_MIR_KHR', commands=[
285    Command(name='CreateMirSurfaceKHR', dispatch='VkInstance'),
286    Command(name='GetPhysicalDeviceMirPresentationSupportKHR', dispatch='VkPhysicalDevice'),
287])
288
289vk_khr_android_surface = Extension(name='VK_KHR_android_surface', version=6, guard='VK_USE_PLATFORM_ANDROID_KHR', commands=[
290    Command(name='CreateAndroidSurfaceKHR', dispatch='VkInstance'),
291])
292
293vk_khr_win32_surface = Extension(name='VK_KHR_win32_surface', version=5, guard='VK_USE_PLATFORM_WIN32_KHR', commands=[
294    Command(name='CreateWin32SurfaceKHR', dispatch='VkInstance'),
295    Command(name='GetPhysicalDeviceWin32PresentationSupportKHR', dispatch='VkPhysicalDevice'),
296])
297
298vk_ext_debug_report = Extension(name='VK_EXT_debug_report', version=1, guard=None, commands=[
299    Command(name='CreateDebugReportCallbackEXT', dispatch='VkInstance'),
300    Command(name='DestroyDebugReportCallbackEXT', dispatch='VkInstance'),
301    Command(name='DebugReportMessageEXT', dispatch='VkInstance'),
302])
303
304extensions = [
305    vk_core,
306    vk_khr_surface,
307    vk_khr_swapchain,
308    vk_khr_display,
309    vk_khr_display_swapchain,
310    vk_khr_xlib_surface,
311    vk_khr_xcb_surface,
312    vk_khr_wayland_surface,
313    vk_khr_mir_surface,
314    vk_khr_android_surface,
315    vk_khr_win32_surface,
316    vk_ext_debug_report,
317]
318
319def generate_header(guard):
320    lines = []
321    lines.append("// This file is generated.")
322    lines.append("#ifndef %s" % guard)
323    lines.append("#define %s" % guard)
324    lines.append("")
325    lines.append("#include <vulkan/vulkan.h>")
326    lines.append("")
327    lines.append("namespace vk {")
328    lines.append("")
329
330    for ext in extensions:
331        if ext.guard:
332            lines.append("#ifdef %s" % ext.guard)
333
334        lines.append("// %s" % ext.name)
335        for cmd in ext.commands:
336            lines.append("extern PFN_vk%s %s;" % (cmd.name, cmd.name))
337
338        if ext.guard:
339            lines.append("#endif")
340        lines.append("")
341
342    lines.append("void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr);")
343    lines.append("void init_dispatch_table_middle(VkInstance instance, bool include_bottom);")
344    lines.append("void init_dispatch_table_bottom(VkInstance instance, VkDevice dev);")
345    lines.append("")
346    lines.append("} // namespace vk")
347    lines.append("")
348    lines.append("#endif // %s" % guard)
349
350    return "\n".join(lines)
351
352def get_proc_addr(dispatchable, cmd, guard=None):
353    if dispatchable == "dev":
354        func = "GetDeviceProcAddr"
355    else:
356        func = "GetInstanceProcAddr"
357
358    c = "    %s = reinterpret_cast<PFN_vk%s>(%s(%s, \"vk%s\"));" % \
359            (cmd.name, cmd.name, func, dispatchable, cmd.name)
360
361    if guard:
362        c = ("#ifdef %s\n" % guard) + c + "\n#endif"
363
364    return c
365
366def generate_source(header):
367    lines = []
368    lines.append("// This file is generated.")
369    lines.append("#include \"%s\"" % header)
370    lines.append("")
371    lines.append("namespace vk {")
372    lines.append("")
373
374    commands_by_types = {}
375    get_instance_proc_addr = None
376    get_device_proc_addr = None
377    for ext in extensions:
378        if ext.guard:
379            lines.append("#ifdef %s" % ext.guard)
380
381        for cmd in ext.commands:
382            lines.append("PFN_vk%s %s;" % (cmd.name, cmd.name))
383
384            if cmd.ty not in commands_by_types:
385                commands_by_types[cmd.ty] = []
386            commands_by_types[cmd.ty].append([cmd, ext.guard])
387
388            if cmd.name == "GetInstanceProcAddr":
389                get_instance_proc_addr = cmd
390            elif cmd.name == "GetDeviceProcAddr":
391                get_device_proc_addr = cmd
392
393        if ext.guard:
394            lines.append("#endif")
395    lines.append("")
396
397    lines.append("void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr)")
398    lines.append("{")
399    lines.append("    GetInstanceProcAddr = get_instance_proc_addr;")
400    lines.append("")
401    for cmd, guard in commands_by_types[Command.LOADER]:
402        lines.append(get_proc_addr("VK_NULL_HANDLE", cmd, guard))
403    lines.append("}")
404    lines.append("")
405
406    lines.append("void init_dispatch_table_middle(VkInstance instance, bool include_bottom)")
407    lines.append("{")
408    lines.append(get_proc_addr("instance", get_instance_proc_addr))
409    lines.append("")
410    for cmd, guard in commands_by_types[Command.INSTANCE]:
411        if cmd == get_instance_proc_addr:
412            continue
413        lines.append(get_proc_addr("instance", cmd, guard))
414    lines.append("")
415    lines.append("    if (!include_bottom)")
416    lines.append("        return;")
417    lines.append("")
418    for cmd, guard in commands_by_types[Command.DEVICE]:
419        lines.append(get_proc_addr("instance", cmd, guard))
420    lines.append("}")
421    lines.append("")
422
423    lines.append("void init_dispatch_table_bottom(VkInstance instance, VkDevice dev)")
424    lines.append("{")
425    lines.append(get_proc_addr("instance", get_device_proc_addr))
426    lines.append(get_proc_addr("dev", get_device_proc_addr))
427    lines.append("")
428    for cmd, guard in commands_by_types[Command.DEVICE]:
429        if cmd == get_device_proc_addr:
430            continue
431        lines.append(get_proc_addr("dev", cmd, guard))
432    lines.append("}")
433
434    lines.append("")
435    lines.append("} // namespace vk")
436
437    return "\n".join(lines)
438
439def parse_vulkan_h(filename):
440    extensions = []
441
442    with open(filename, "r") as f:
443        current_ext = None
444        ext_guard = None
445        spec_version = None
446
447        for line in f:
448            line = line.strip();
449
450            if line.startswith("#define VK_API_VERSION"):
451                minor_end = line.rfind(",")
452                minor_begin = line.rfind(",", 0, minor_end) + 1
453                spec_version = int(line[minor_begin:minor_end])
454                # add core
455                current_ext = Extension("VK_core", spec_version)
456                extensions.append(current_ext)
457            elif Command.valid_c_typedef(line):
458                current_ext.add_command(Command.from_c_typedef(line))
459            elif line.startswith("#ifdef VK_USE_PLATFORM"):
460                guard_begin = line.find(" ") + 1
461                ext_guard = line[guard_begin:]
462            elif line.startswith("#define") and "SPEC_VERSION " in line:
463                version_begin = line.rfind(" ") + 1
464                spec_version = int(line[version_begin:])
465            elif line.startswith("#define") and "EXTENSION_NAME " in line:
466                name_end = line.rfind("\"")
467                name_begin = line.rfind("\"", 0, name_end) + 1
468                name = line[name_begin:name_end]
469                # add extension
470                current_ext = Extension(name, spec_version, ext_guard)
471                extensions.append(current_ext)
472            elif ext_guard and line.startswith("#endif") and ext_guard in line:
473                ext_guard = None
474
475    for ext in extensions:
476        print("%s = %s" % (ext.name.lower(), repr(ext)))
477        print("")
478
479    print("extensions = [")
480    for ext in extensions:
481        print("    %s," % ext.name.lower())
482    print("]")
483
484if __name__ == "__main__":
485    if sys.argv[1] == "parse":
486        parse_vulkan_h(sys.argv[2])
487    else:
488        filename = sys.argv[1]
489        base = os.path.basename(filename)
490        contents = []
491
492        if base.endswith(".h"):
493            contents = generate_header(base.replace(".", "_").upper())
494        elif base.endswith(".cpp"):
495            contents = generate_source(base.replace(".cpp", ".h"))
496
497        with open(filename, "w") as f:
498            print(contents, file=f)
499