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