1 /// Vulkan queue module
2 module gfx.vulkan.queue;
3 
4 package:
5 
6 import gfx.bindings.vulkan;
7 
8 import gfx.core.rc;
9 import gfx.graal.queue;
10 import gfx.vulkan.conv;
11 import gfx.vulkan.device;
12 import gfx.vulkan.error;
13 import gfx.vulkan.sync;
14 import gfx.vulkan.wsi;
15 
16 final class VulkanQueue : Queue
17 {
18     this (VkQueue vkObj, VulkanDevice dev) {
19         _vkObj = vkObj;
20         _dev = dev; // weak reference, no retain
21         _vk = dev.vk;
22     }
23 
24     @property VkQueue vkObj() {
25         return _vkObj;
26     }
27 
28     @property VkDeviceCmds vk() {
29         return _vk;
30     }
31 
32     @property Device device()
33     {
34         auto dev = lockObj(_dev);
35         if (!dev) return null;
36         return giveAwayObj(dev);
37     }
38 
39     void waitIdle() {
40         vk.QueueWaitIdle(_vkObj);
41     }
42 
43     void submit(Submission[] submissions, Fence fence)
44     {
45         import std.algorithm : map;
46         import std.array : array;
47 
48         auto vkSubmitInfos = submissions.map!((ref Submission s)
49         {
50             auto vkWaitSems = new VkSemaphore[s.stageWaits.length];
51             auto vkWaitDstStage = new VkPipelineStageFlags[s.stageWaits.length];
52 
53             foreach (i, sw; s.stageWaits) {
54                 vkWaitSems[i] = enforce(
55                     cast(VulkanSemaphore)sw.sem,
56                     "Did not pass a valid vulkan wait semaphore to VulkanQueue.submit()"
57                 ).vkObj;
58                 vkWaitDstStage[i] = pipelineStageToVk(sw.stages);
59             }
60 
61             auto vkSigSems = s.sigSems.map!(
62                 s => enforce(
63                     cast(VulkanSemaphore)s,
64                     "Did not pass a valid vulkan signal semaphore to VulkanQueue.submit()"
65                 ).vkObj
66             ).array;
67             auto vkCmdBufs = s.cmdBufs.map!(
68                 b => enforce(
69                     cast(VulkanCommandBuffer)b,
70                     "Did not pass a vulkan command buffer"
71                 ).vkObj
72             ).array;
73 
74 
75             VkSubmitInfo si;
76             si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
77             si.waitSemaphoreCount = cast(uint)vkWaitSems.length;
78             si.pWaitSemaphores = vkWaitSems.ptr;
79             si.pWaitDstStageMask = vkWaitDstStage.ptr;
80             si.commandBufferCount = cast(uint)vkCmdBufs.length;
81             si.pCommandBuffers = vkCmdBufs.ptr;
82             si.signalSemaphoreCount = cast(uint)vkSigSems.length;
83             si.pSignalSemaphores = vkSigSems.ptr;
84 
85             return si;
86         }).array;
87 
88         VkFence vkFence;
89         if (fence) {
90             vkFence = enforce(cast(VulkanFence)fence, "Did not pass a Vulkan fence").vkObj;
91         }
92 
93         vulkanEnforce(
94             vk.QueueSubmit(vkObj, cast(uint)vkSubmitInfos.length, vkSubmitInfos.ptr, vkFence),
95             "Could not submit vulkan queue"
96         );
97     }
98 
99     void present(Semaphore[] waitSems, PresentRequest[] prs) {
100         import std.algorithm : map;
101         import std.array : array;
102 
103         auto vkSems = waitSems.map!(
104             s => enforce(
105                 cast(VulkanSemaphore)s,
106                 "Did not pass a valid vulkan wait semaphore to VulkanQueue.present()"
107             ).vkObj
108         ).array;
109 
110         auto vkScs = new VkSwapchainKHR[prs.length];
111         auto vkImgs = new uint[prs.length];
112         foreach (i, pr; prs) {
113             vkScs[i] = enforce(
114                 cast(VulkanSwapchain)pr.swapChain,
115                 "Did not pass a vukan swap chain").vkObj;
116             vkImgs[i] = pr.imageIndex;
117         }
118 
119         VkPresentInfoKHR qpi;
120         qpi.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
121         qpi.waitSemaphoreCount = cast(uint)waitSems.length;
122         qpi.pWaitSemaphores = &vkSems[0];
123         qpi.swapchainCount = cast(uint)prs.length;
124         qpi.pSwapchains = &vkScs[0];
125         qpi.pImageIndices = &vkImgs[0];
126 
127         vulkanEnforce(
128             vk.QueuePresentKHR(vkObj, &qpi), "Could not present vulkan swapchain"
129         );
130     }
131 
132     private VkQueue _vkObj;
133     private VulkanDevice _dev; // device is kept as weak reference
134     private VkDeviceCmds _vk;
135 }