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