1 
2 /// Loader module for vkdgen.
3 /// Loading bindings is done in 3 steps as follow:
4 /// ---
5 /// import gfx.bindings.vulkan.loader;
6 ///
7 /// // load global commands
8 /// auto globVk = loadVulkanGlobalCmds();
9 ///
10 /// // load instance commands
11 /// VkInstance inst;
12 /// VkInstanceCreateInfo instCreateInfo = // ...
13 /// globVk.CreateInstance(&instCreateInfo, null, &inst);
14 /// auto instVk = new VkInstanceCmds(inst, globVk);
15 ///
16 /// // load device commands
17 /// VkPhysicalDevice phDev = // ...
18 /// VkDevice dev;
19 /// VkDeviceCreateInfo devCreateInfo = // ...
20 /// instVk.CreateDevice(phDev, &devCreateInfo, null, &dev);
21 /// auto vk = new VkDeviceCmds(dev, instVk);
22 ///
23 /// // vk.CreateBuffer(dev, ...);
24 /// ---
25 module gfx.bindings.vulkan.loader;
26 
27 import gfx.bindings.vulkan.vk : VkGlobalCmds;
28 
29 import std.exception;
30 
31 /// A handle to a shared library
32 alias SharedLib = void*;
33 /// A handle to a shared library symbol
34 alias SharedSym = void*;
35 
36 /// Opens a shared library.
37 /// Return null in case of failure.
38 SharedLib openSharedLib(string name);
39 
40 /// Load a symbol from a shared library.
41 /// Return null in case of failure.
42 SharedSym loadSharedSym(SharedLib lib, string name);
43 
44 /// Close a shared library
45 void closeSharedLib(SharedLib lib);
46 
47 
48 /// Generic Dynamic lib symbol loader.
49 /// Symbols loaded with such loader must be cast to the appropriate function type.
50 alias SymbolLoader = SharedSym delegate (in string name);
51 
52 
53 version(Posix)
54 {
55     import std..string : toStringz;
56     import core.sys.posix.dlfcn;
57 
58     SharedLib openSharedLib(string name)
59     {
60         return dlopen(toStringz(name), RTLD_LAZY);
61     }
62 
63     SharedSym loadSharedSym(SharedLib lib, string name)
64     {
65         return dlsym(lib, toStringz(name));
66     }
67 
68     void closeSharedLib(SharedLib lib)
69     {
70         dlclose(lib);
71     }
72 }
73 version(Windows)
74 {
75     import std..string : toStringz;
76     import core.sys.windows.winbase;
77 
78     SharedLib openSharedLib(string name)
79     {
80         return LoadLibraryA(toStringz(name));
81     }
82 
83     SharedSym loadSharedSym(SharedLib lib, string name)
84     {
85         return GetProcAddress(lib, toStringz(name));
86     }
87 
88     void closeSharedLib(SharedLib lib)
89     {
90         FreeLibrary(lib);
91     }
92 }
93 
94 /// Load global commands from Vulkan DLL/Shared object.
95 /// Returns: a VkGlobalCmds object
96 VkGlobalCmds loadVulkanGlobalCmds()
97 {
98     import gfx.bindings.vulkan.vk : PFN_vkGetInstanceProcAddr;
99 
100     version( Windows )
101         enum libName = "vulkan-1.dll";
102     else version ( OSX )
103         enum libName = "libMoltenVK.dylib";
104     else version( Posix )
105         enum libName = "libvulkan.so.1";
106     else
107         static assert (false, "Vulkan bindings not supported on this OS");
108 
109     auto lib = enforce(openSharedLib(libName), "Cannot open "~libName);
110 
111     auto getInstanceProcAddr = enforce(
112         cast(PFN_vkGetInstanceProcAddr)loadSharedSym(lib, "vkGetInstanceProcAddr"),
113         "Could not load vkGetInstanceProcAddr from "~libName
114     );
115 
116     return new VkGlobalCmds(getInstanceProcAddr);
117 }