1 /// Vulkan command module 2 module gfx.vulkan.cmd; 3 4 package: 5 6 import gfx.bindings.vulkan; 7 8 import gfx.core.rc; 9 import gfx.core.typecons; 10 import gfx.graal.cmd; 11 import gfx.graal.renderpass; 12 import gfx.vulkan.buffer; 13 import gfx.vulkan.conv; 14 import gfx.vulkan.device; 15 import gfx.vulkan.error; 16 import gfx.vulkan.image; 17 import gfx.vulkan.renderpass; 18 19 import std.typecons : Flag; 20 21 class VulkanCommandPool : VulkanDevObj!(VkCommandPool, "destroyCommandPool"), CommandPool 22 { 23 mixin(atomicRcCode); 24 25 this (VkCommandPool pool, VulkanDevice dev) { 26 super(pool, dev); 27 } 28 29 override void reset() { 30 vulkanEnforce(cmds.resetCommandPool(vkDev, vk, 0), "Could not reset command buffer"); 31 } 32 33 override CommandBuffer[] allocate(size_t count) { 34 VkCommandBufferAllocateInfo cbai; 35 cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 36 cbai.commandPool = vk; 37 cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 38 cbai.commandBufferCount = cast(uint)count; 39 40 auto vkBufs = new VkCommandBuffer[count]; 41 vulkanEnforce( 42 cmds.allocateCommandBuffers(vkDev, &cbai, &vkBufs[0]), 43 "Could not allocate command buffers" 44 ); 45 46 import std.algorithm : map; 47 import std.array : array; 48 49 return vkBufs 50 .map!(vkBuf => cast(CommandBuffer)new VulkanCommandBuffer(vkBuf, this)) 51 .array; 52 } 53 54 override void free(CommandBuffer[] bufs) { 55 import std.algorithm : map; 56 import std.array : array; 57 58 auto vkBufs = bufs.map!( 59 b => enforce(cast(VulkanCommandBuffer)b, "Did not pass a Vulkan command buffer").vk 60 ).array; 61 cmds.freeCommandBuffers(vkDev, vk, cast(uint)bufs.length, &vkBufs[0]); 62 } 63 } 64 65 final class VulkanCommandBuffer : CommandBuffer 66 { 67 this (VkCommandBuffer vk, VulkanCommandPool pool) { 68 _vk = vk; 69 _pool = pool; 70 _cmds = pool.cmds; 71 } 72 73 @property VkCommandBuffer vk() { 74 return _vk; 75 } 76 77 override @property CommandPool pool() { 78 return _pool; 79 } 80 81 @property VkDeviceCmds cmds() { 82 return _cmds; 83 } 84 85 override void reset() { 86 vulkanEnforce( 87 cmds.resetCommandBuffer(vk, 0), "Could not reset vulkan command buffer" 88 ); 89 } 90 91 override void begin(Flag!"persistent" persistent) { 92 VkCommandBufferBeginInfo cbbi; 93 cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 94 cbbi.flags = persistent ? 95 VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT : 96 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; 97 vulkanEnforce( 98 cmds.beginCommandBuffer(vk, &cbbi), "Could not begin vulkan command buffer" 99 ); 100 } 101 102 override void end() { 103 vulkanEnforce( 104 cmds.endCommandBuffer(vk), "Could not end vulkan command buffer" 105 ); 106 } 107 108 override void pipelineBarrier(Trans!PipelineStage stageTrans, 109 BufferMemoryBarrier[] bufMbs, 110 ImageMemoryBarrier[] imgMbs) 111 { 112 import std.algorithm : map; 113 import std.array : array; 114 115 auto vkBufMbs = bufMbs.map!((BufferMemoryBarrier bufMb) { 116 VkBufferMemoryBarrier vkBufMb; 117 vkBufMb.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 118 vkBufMb.srcAccessMask = accessToVk(bufMb.accessMaskTrans.from); 119 vkBufMb.dstAccessMask = accessToVk(bufMb.accessMaskTrans.to); 120 vkBufMb.srcQueueFamilyIndex = bufMb.queueFamIndexTrans.from; 121 vkBufMb.dstQueueFamilyIndex = bufMb.queueFamIndexTrans.to; 122 vkBufMb.buffer = enforce(cast(VulkanBuffer)bufMb.buffer, "Did not pass a Vulkan buffer").vk; 123 vkBufMb.offset = bufMb.offset; 124 vkBufMb.size = bufMb.size; 125 return vkBufMb; 126 }).array; 127 128 auto vkImgMbs = imgMbs.map!((ImageMemoryBarrier imgMb) { 129 VkImageMemoryBarrier vkImgMb; 130 vkImgMb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 131 vkImgMb.srcAccessMask = accessToVk(imgMb.accessMaskTrans.from); 132 vkImgMb.dstAccessMask = accessToVk(imgMb.accessMaskTrans.to); 133 vkImgMb.oldLayout = imgMb.layoutTrans.from.toVk(); 134 vkImgMb.newLayout = imgMb.layoutTrans.to.toVk(); 135 vkImgMb.srcQueueFamilyIndex = imgMb.queueFamIndexTrans.from; 136 vkImgMb.dstQueueFamilyIndex = imgMb.queueFamIndexTrans.to; 137 vkImgMb.image = enforce(cast(VulkanImage)imgMb.image, "Did not pass a Vulkan image").vk; 138 vkImgMb.subresourceRange = imgMb.range.toVk(); 139 return vkImgMb; 140 }).array; 141 142 cmds.cmdPipelineBarrier( vk, 143 pipelineStageToVk(stageTrans.from), pipelineStageToVk(stageTrans.to), 144 0, 0, null, 145 cast(uint)vkBufMbs.length, vkBufMbs.ptr, 146 cast(uint)vkImgMbs.length, vkImgMbs.ptr 147 ); 148 } 149 150 override void clearColorImage(Image image, ImageLayout layout, 151 in ClearColorValues clearValues, ImageSubresourceRange[] ranges) 152 { 153 import std.algorithm : map; 154 import std.array : array; 155 156 auto vkImg = enforce(cast(VulkanImage)image, "Did not pass a vulkan image").vk; 157 auto vkLayout = layout.toVk(); 158 auto vkClear = cast(const(VkClearColorValue)*) cast(const(void)*) &clearValues.values; 159 auto vkRanges = ranges.map!(r => r.toVk()).array; 160 161 cmds.cmdClearColorImage(vk, vkImg, vkLayout, vkClear, cast(uint)vkRanges.length, &vkRanges[0]); 162 } 163 164 override void clearDepthStencilImage(Image image, ImageLayout layout, 165 in ClearDepthStencilValues clearValues, 166 ImageSubresourceRange[] ranges) 167 { 168 import std.algorithm : map; 169 import std.array : array; 170 171 auto vkImg = enforce(cast(VulkanImage)image, "Did not pass a vulkan image").vk; 172 auto vkLayout = layout.toVk(); 173 auto vkClear = VkClearDepthStencilValue(clearValues.depth, clearValues.stencil); 174 auto vkRanges = ranges.map!(r => r.toVk()).array; 175 176 cmds.cmdClearDepthStencilImage(vk, vkImg, vkLayout, &vkClear, cast(uint)vkRanges.length, &vkRanges[0]); 177 } 178 179 override void beginRenderPass(RenderPass rp, Framebuffer fb, 180 Rect area, ClearValues[] clearValues) 181 { 182 import std.algorithm : map; 183 import std.array : array; 184 auto vkCvs = clearValues.map!( 185 (ClearValues cv) { 186 VkClearValue vkCv; 187 if (cv.type == ClearValues.Type.color) { 188 const ccv = cv.values.color; 189 VkClearColorValue vkCcv; 190 switch (ccv.type) { 191 case ClearColorValues.Type.f32: 192 vkCcv.float32 = ccv.values.f32; 193 break; 194 case ClearColorValues.Type.i32: 195 vkCcv.int32 = ccv.values.i32; 196 break; 197 case ClearColorValues.Type.u32: 198 vkCcv.uint32 = ccv.values.u32; 199 break; 200 default: 201 break; 202 } 203 vkCv.color = vkCcv; 204 } 205 else if (cv.type == ClearValues.Type.depthStencil) { 206 const dscv = cv.values.depthStencil; 207 vkCv.depthStencil = VkClearDepthStencilValue( 208 dscv.depth, dscv.stencil 209 ); 210 } 211 return vkCv; 212 } 213 ).array; 214 215 VkRenderPassBeginInfo bi; 216 bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 217 bi.renderPass = enforce(cast(VulkanRenderPass)rp, "did not supply a valid Vulkan render pass").vk; 218 bi.framebuffer = enforce(cast(VulkanFramebuffer)fb, "did not supply a valid Vulkan frame buffer").vk; 219 bi.renderArea = area.toVk(); 220 bi.clearValueCount = cast(uint)vkCvs.length; 221 bi.pClearValues = vkCvs.ptr; 222 223 cmds.cmdBeginRenderPass(vk, &bi, VK_SUBPASS_CONTENTS_INLINE); 224 } 225 226 override void nextSubpass() { 227 cmds.cmdNextSubpass(vk, VK_SUBPASS_CONTENTS_INLINE); 228 } 229 230 override void endRenderPass() { 231 cmds.cmdEndRenderPass(vk); 232 } 233 234 override void bindPipeline(Pipeline pipeline) 235 { 236 cmds.cmdBindPipeline(vk, VK_PIPELINE_BIND_POINT_GRAPHICS, enforce( 237 cast(VulkanPipeline)pipeline, "did not pass a valid Vulkan pipeline" 238 ).vk); 239 } 240 241 override void bindVertexBuffers(uint firstBinding, VertexBinding[] bindings) { 242 import std.algorithm : map; 243 import std.array : array; 244 auto vkBufs = bindings 245 .map!(b => enforce(cast(VulkanBuffer)b.buffer).vk) 246 .array; 247 auto vkOffsets = bindings 248 .map!(b => cast(VkDeviceSize)b.offset) 249 .array; 250 cmds.cmdBindVertexBuffers(vk, firstBinding, cast(uint)bindings.length, vkBufs.ptr, vkOffsets.ptr); 251 } 252 253 254 override void draw(uint vertexCount, uint instanceCount, uint firstVertex, uint firstInstance) 255 { 256 cmds.cmdDraw(vk, vertexCount, instanceCount, firstVertex, firstInstance); 257 } 258 259 private VkCommandBuffer _vk; 260 private VulkanCommandPool _pool; 261 private VkDeviceCmds _cmds; 262 }