1 module sbylib.graphics.wrapper.device;
2 
3 import std;
4 import erupted;
5 import sbylib.wrapper.vulkan;
6 import sbylib.wrapper.glfw : Window, GLFW;
7 import sbylib.graphics.layer;
8 import sbylib.graphics.util.functions;
9 import sbylib.graphics.wrapper.fence;
10 import sbylib.graphics.wrapper.queue;
11 
12 class VDevice {
13 
14     struct CreateInfo {
15         VkPhysicalDeviceFeatures features;
16         LayerSettings layerSettings;
17         string appName;
18         uint appVersion;
19     }
20 
21     Instance instance;
22     PhysicalDevice gpu;
23     Device device;
24     alias device this;
25 
26     private LayerSettings layerSettings;
27 
28     mixin ImplResourceStack;
29 
30     static void initialize(CreateInfo info, Window window) {
31         import erupted.vulkan_lib_loader : loadGlobalLevelFunctions;
32 
33         const globalFunctionLoaded = loadGlobalLevelFunctions();
34         assert(globalFunctionLoaded);
35 
36         info.layerSettings.settings ~= new StandardValidationLayerSetting;
37         info.layerSettings.settings ~= new KhronosValidationLayerSetting;
38         scope (exit) info.layerSettings.finalize();
39 
40         Instance.CreateInfo instanceCreateInfo = {
41             applicationInfo: {
42                 applicationName: info.appName,
43                 applicationVersion: info.appVersion,
44                 engineName: "sbylib",
45                 engineVersion: VK_MAKE_VERSION(1,0,0),
46                 apiVersion : VK_API_VERSION_1_0
47             },
48             enabledLayerNames: info.layerSettings.use(),
49             enabledExtensionNames: GLFW.getRequiredInstanceExtensions() ~ ["VK_EXT_debug_report"]
50         };
51 
52         enforce(instanceCreateInfo.enabledLayerNames.all!(n =>
53                     LayerProperties.getAvailableInstanceLayerProperties().canFind!(l => l.layerName == n)));
54 
55         auto instance = new Instance(instanceCreateInfo);
56 
57         inst = new VDevice(instance, info.features, window);
58     }
59 
60     static void deinitialize() {
61         inst.destroyStack();
62     }
63 
64     private static typeof(this) inst;
65 
66     static typeof(this) opCall() {
67         return inst;
68     }
69 
70     private this(Instance instance, VkPhysicalDeviceFeatures feature, Window window) {
71         this.instance = instance;
72 
73         auto surface = window.createSurface(instance);
74         scope (exit)
75             surface.destroy();
76 
77         this.gpu = instance.findPhysicalDevice!((PhysicalDevice gpu) => gpu.getSurfaceSupport(surface));
78 
79         this.device = createDevice(feature);
80 
81         pushResource(instance);
82         pushResource(device);
83     }
84 
85     public uint findQueueFamilyIndex(QueueFamilyProperties.Flags flags) {
86         return gpu.findQueueFamilyIndex!(prop => prop.supports(flags));
87     }
88 
89     private Device createDevice(VkPhysicalDeviceFeatures features) {
90         auto graphicsQueueFamilyIndex = findQueueFamilyIndex(QueueFamilyProperties.Flags.Graphics);
91         auto computeQueueFamilyIndex = findQueueFamilyIndex(QueueFamilyProperties.Flags.Compute);
92         Device.QueueCreateInfo[] queueCreateInfos = [{
93             queuePriorities: [0.0f],
94             queueFamilyIndex: graphicsQueueFamilyIndex,
95         }];
96         if (graphicsQueueFamilyIndex != computeQueueFamilyIndex) {
97             Device.QueueCreateInfo computeQueueCreateInfo = {
98                 queuePriorities: [0.0f],
99                 queueFamilyIndex: computeQueueFamilyIndex,
100             };
101             queueCreateInfos ~= computeQueueCreateInfo;
102         }
103         Device.DeviceCreateInfo deviceCreateInfo = {
104             queueCreateInfos: queueCreateInfos,
105             enabledExtensionNames: ["VK_KHR_swapchain", "VK_EXT_debug_marker"],
106             pEnabledFeatures: &features
107         };
108         return new Device(gpu, deviceCreateInfo);
109     }
110 }