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(vk.ResetCommandPool(vkDev, vkObj, 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 = vkObj; 37 cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 38 cbai.commandBufferCount = cast(uint)count; 39 40 auto vkBufs = new VkCommandBuffer[count]; 41 vulkanEnforce( 42 vk.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").vkObj 60 ).array; 61 vk.FreeCommandBuffers(vkDev, vkObj, cast(uint)bufs.length, &vkBufs[0]); 62 } 63 } 64 65 final class VulkanCommandBuffer : CommandBuffer 66 { 67 this (VkCommandBuffer vkObj, VulkanCommandPool pool) { 68 _vkObj = vkObj; 69 _pool = pool; 70 _vk = pool.vk; 71 } 72 73 @property VkCommandBuffer vkObj() { 74 return _vkObj; 75 } 76 77 override @property CommandPool pool() { 78 return _pool; 79 } 80 81 @property VkDeviceCmds vk() { 82 return _vk; 83 } 84 85 override void reset() { 86 vulkanEnforce( 87 vk.ResetCommandBuffer(vkObj, 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 vk.BeginCommandBuffer(vkObj, &cbbi), "Could not begin vulkan command buffer" 99 ); 100 } 101 102 override void end() { 103 vulkanEnforce( 104 vk.EndCommandBuffer(vkObj), "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").vkObj; 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(VulkanImageBase)imgMb.image, "Did not pass a Vulkan image").vkObj; 138 vkImgMb.subresourceRange = imgMb.range.toVk(); 139 return vkImgMb; 140 }).array; 141 142 vk.CmdPipelineBarrier( vkObj, 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(ImageBase 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(VulkanImageBase)image, "Did not pass a vulkan image").vkObj; 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 vk.CmdClearColorImage(vkObj, vkImg, vkLayout, vkClear, cast(uint)vkRanges.length, &vkRanges[0]); 162 } 163 164 override void clearDepthStencilImage(ImageBase 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(VulkanImageBase)image, "Did not pass a vulkan image").vkObj; 172 auto vkLayout = layout.toVk(); 173 auto vkClear = VkClearDepthStencilValue(clearValues.depth, clearValues.stencil); 174 auto vkRanges = ranges.map!(r => r.toVk()).array; 175 176 vk.CmdClearDepthStencilImage(vkObj, vkImg, vkLayout, &vkClear, cast(uint)vkRanges.length, &vkRanges[0]); 177 } 178 179 override void fillBuffer(Buffer dst, in size_t offset, in size_t size, uint value) 180 { 181 auto vkBuf = enforce(cast(VulkanBuffer)dst, "Did not pass a valid vulkan buffer to fillBuffer").vkObj; 182 vk.CmdFillBuffer(vkObj, vkBuf, offset, size, value); 183 } 184 185 override void updateBuffer(Buffer dst, in size_t offset, in uint[] data) 186 { 187 auto vkBuf = enforce(cast(VulkanBuffer)dst, "Did not pass a valid vulkan buffer to updateBuffer").vkObj; 188 vk.CmdUpdateBuffer(vkObj, vkBuf, offset, 4*data.length, cast(void*)data.ptr); 189 } 190 191 override void copyBuffer(Trans!Buffer buffers, in CopyRegion[] regions) 192 { 193 import std.algorithm : map; 194 import std.array : array; 195 196 auto vkRegions = regions.map!( 197 r => VkBufferCopy(r.offset.from, r.offset.to, r.size) 198 ).array; 199 200 vk.CmdCopyBuffer(vkObj, 201 enforce(cast(VulkanBuffer)buffers.from).vkObj, 202 enforce(cast(VulkanBuffer)buffers.to).vkObj, 203 cast(uint)vkRegions.length, vkRegions.ptr 204 ); 205 } 206 207 void copyBufferToImage(Buffer srcBuffer, ImageBase dstImage, 208 in ImageLayout dstLayout, in BufferImageCopy[] regions) 209 { 210 import gfx.core.util : transmute; 211 import std.algorithm : map; 212 import std.array : array; 213 214 auto vkRegions = regions.map!( 215 bic => transmute!VkBufferImageCopy(bic) 216 ).array; 217 218 vk.CmdCopyBufferToImage( 219 vkObj, 220 enforce(cast(VulkanBuffer)srcBuffer).vkObj, 221 enforce(cast(VulkanImageBase)dstImage).vkObj, 222 dstLayout.toVk(), 223 cast(uint)vkRegions.length, vkRegions.ptr 224 ); 225 } 226 227 override void setViewport(in uint firstViewport, in Viewport[] viewports) 228 { 229 import gfx.core.util : transmute; 230 const vkVp = transmute!(const(VkViewport)[])(viewports); 231 vk.CmdSetViewport(vkObj, firstViewport, cast(uint)vkVp.length, vkVp.ptr); 232 } 233 234 override void setScissor(in uint firstScissor, in Rect[] scissors) 235 { 236 import gfx.core.util : transmute; 237 const vkSc = transmute!(const(VkRect2D)[])(scissors); 238 vk.CmdSetScissor(vkObj, firstScissor, cast(uint)vkSc.length, vkSc.ptr); 239 } 240 241 override void setDepthBounds(in float minDepth, in float maxDepth) 242 { 243 vk.CmdSetDepthBounds(vkObj, minDepth, maxDepth); 244 } 245 246 override void setLineWidth(in float lineWidth) 247 { 248 vk.CmdSetLineWidth(vkObj, lineWidth); 249 } 250 251 override void setDepthBias(in float constFactor, in float clamp, in float slopeFactor) 252 { 253 vk.CmdSetDepthBias(vkObj, constFactor, clamp, slopeFactor); 254 } 255 256 override void setStencilCompareMask(in StencilFace faceMask, in uint compareMask) 257 { 258 vk.CmdSetStencilCompareMask(vkObj, cast(VkStencilFaceFlags)faceMask, compareMask); 259 } 260 261 override void setStencilWriteMask(in StencilFace faceMask, in uint writeMask) 262 { 263 vk.CmdSetStencilWriteMask(vkObj, cast(VkStencilFaceFlags)faceMask, writeMask); 264 } 265 266 override void setStencilReference(in StencilFace faceMask, in uint reference) 267 { 268 vk.CmdSetStencilReference(vkObj, cast(VkStencilFaceFlags)faceMask, reference); 269 } 270 271 override void setBlendConstants(in float[4] blendConstants) 272 { 273 vk.CmdSetBlendConstants(vkObj, blendConstants); 274 } 275 276 override void beginRenderPass(RenderPass rp, Framebuffer fb, 277 Rect area, ClearValues[] clearValues) 278 { 279 import std.algorithm : map; 280 import std.array : array; 281 auto vkCvs = clearValues.map!( 282 (ClearValues cv) { 283 VkClearValue vkCv; 284 if (cv.type == ClearValues.Type.color) { 285 const ccv = cv.values.color; 286 VkClearColorValue vkCcv; 287 switch (ccv.type) { 288 case ClearColorValues.Type.f32: 289 vkCcv.float32 = ccv.values.f32; 290 break; 291 case ClearColorValues.Type.i32: 292 vkCcv.int32 = ccv.values.i32; 293 break; 294 case ClearColorValues.Type.u32: 295 vkCcv.uint32 = ccv.values.u32; 296 break; 297 default: 298 break; 299 } 300 vkCv.color = vkCcv; 301 } 302 else if (cv.type == ClearValues.Type.depthStencil) { 303 const dscv = cv.values.depthStencil; 304 vkCv.depthStencil = VkClearDepthStencilValue( 305 dscv.depth, dscv.stencil 306 ); 307 } 308 return vkCv; 309 } 310 ).array; 311 312 VkRenderPassBeginInfo bi; 313 bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 314 bi.renderPass = enforce(cast(VulkanRenderPass)rp, "did not supply a valid Vulkan render pass").vkObj; 315 bi.framebuffer = enforce(cast(VulkanFramebuffer)fb, "did not supply a valid Vulkan frame buffer").vkObj; 316 bi.renderArea = area.toVk(); 317 bi.clearValueCount = cast(uint)vkCvs.length; 318 bi.pClearValues = vkCvs.ptr; 319 320 vk.CmdBeginRenderPass(vkObj, &bi, VK_SUBPASS_CONTENTS_INLINE); 321 } 322 323 override void nextSubpass() { 324 vk.CmdNextSubpass(vkObj, VK_SUBPASS_CONTENTS_INLINE); 325 } 326 327 override void endRenderPass() { 328 vk.CmdEndRenderPass(vkObj); 329 } 330 331 override void bindPipeline(Pipeline pipeline) 332 { 333 vk.CmdBindPipeline(vkObj, VK_PIPELINE_BIND_POINT_GRAPHICS, enforce( 334 cast(VulkanPipeline)pipeline, "did not pass a valid Vulkan pipeline" 335 ).vkObj); 336 } 337 338 override void bindVertexBuffers(uint firstBinding, VertexBinding[] bindings) { 339 import std.algorithm : map; 340 import std.array : array; 341 auto vkBufs = bindings 342 .map!(b => enforce(cast(VulkanBuffer)b.buffer).vkObj) 343 .array; 344 auto vkOffsets = bindings 345 .map!(b => cast(VkDeviceSize)b.offset) 346 .array; 347 vk.CmdBindVertexBuffers(vkObj, firstBinding, cast(uint)bindings.length, vkBufs.ptr, vkOffsets.ptr); 348 } 349 350 override void bindIndexBuffer(Buffer indexBuf, size_t offset, IndexType type) { 351 auto vkBuf = enforce(cast(VulkanBuffer)indexBuf).vkObj; 352 vk.CmdBindIndexBuffer(vkObj, vkBuf, offset, type.toVk()); 353 } 354 355 override void bindDescriptorSets(PipelineBindPoint bindPoint, PipelineLayout layout, 356 uint firstSet, DescriptorSet[] sets, 357 in size_t[] dynamicOffsets) 358 { 359 import std.algorithm : map; 360 import std.array : array; 361 362 auto vkSets = sets.map!(s => enforce(cast(VulkanDescriptorSet)s).vkObj).array; 363 static if (size_t.sizeof == uint.sizeof) { 364 const vkOffsets = dynamicOffsets; 365 } 366 else { 367 const vkOffsets = dynamicOffsets.map!(o => cast(uint)o).array; 368 } 369 370 vk.CmdBindDescriptorSets( vkObj, bindPoint.toVk(), 371 enforce(cast(VulkanPipelineLayout)layout).vkObj, 372 firstSet, cast(uint)vkSets.length, vkSets.ptr, 373 cast(uint)vkOffsets.length, vkOffsets.ptr); 374 } 375 376 override void pushConstants(PipelineLayout layout, ShaderStage stages, 377 size_t offset, size_t size, const(void)* data) 378 { 379 auto vkPl = enforce(cast(VulkanPipelineLayout)layout).vkObj; 380 vk.CmdPushConstants(vkObj, vkPl, shaderStageToVk(stages), cast(uint)offset, cast(uint)size, data); 381 } 382 383 override void draw(uint vertexCount, uint instanceCount, uint firstVertex, uint firstInstance) 384 { 385 vk.CmdDraw(vkObj, vertexCount, instanceCount, firstVertex, firstInstance); 386 } 387 388 override void drawIndexed(uint indexCount, uint instanceCount, uint firstVertex, int vertexOffset, uint firstInstance) 389 { 390 vk.CmdDrawIndexed(vkObj, indexCount, instanceCount, firstVertex, vertexOffset, firstInstance); 391 } 392 393 private VkCommandBuffer _vkObj; 394 private VulkanCommandPool _pool; 395 private VkDeviceCmds _vk; 396 }