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 mixin(atomicRcCode); 23 24 this(VkCommandPool pool, VulkanDevice dev) { 25 super(pool, dev); 26 } 27 28 override void reset() { 29 vulkanEnforce(vk.ResetCommandPool(vkDev, vkObj, 0), "Could not reset command buffer"); 30 } 31 32 override PrimaryCommandBuffer[] allocatePrimary(in size_t count) { 33 VkCommandBufferAllocateInfo cbai; 34 cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 35 cbai.commandPool = vkObj; 36 cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 37 cbai.commandBufferCount = cast(uint) count; 38 39 auto vkBufs = new VkCommandBuffer[count]; 40 vulkanEnforce(vk.AllocateCommandBuffers(vkDev, &cbai, &vkBufs[0]), 41 "Could not allocate command buffers"); 42 43 import std.algorithm : map; 44 import std.array : array; 45 46 return vkBufs.map!(vkBuf => cast(PrimaryCommandBuffer) new VulkanCommandBuffer(vkBuf, 47 this, CommandBufferLevel.primary)).array; 48 } 49 50 override SecondaryCommandBuffer[] allocateSecondary(in size_t count) { 51 VkCommandBufferAllocateInfo cbai; 52 cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 53 cbai.commandPool = vkObj; 54 cbai.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; 55 cbai.commandBufferCount = cast(uint) count; 56 57 auto vkBufs = new VkCommandBuffer[count]; 58 vulkanEnforce(vk.AllocateCommandBuffers(vkDev, &cbai, &vkBufs[0]), 59 "Could not allocate command buffers"); 60 61 import std.algorithm : map; 62 import std.array : array; 63 64 return vkBufs.map!(vkBuf => cast(SecondaryCommandBuffer) new VulkanCommandBuffer(vkBuf, 65 this, CommandBufferLevel.secondary)).array; 66 } 67 68 override void free(CommandBuffer[] bufs) { 69 import std.algorithm : map; 70 import std.array : array; 71 72 auto vkBufs = bufs.map!(b => enforce(cast(VulkanCommandBuffer) b, 73 "Did not pass a Vulkan command buffer").vkObj).array; 74 vk.FreeCommandBuffers(vkDev, vkObj, cast(uint) bufs.length, &vkBufs[0]); 75 } 76 } 77 78 final class VulkanCommandBuffer : PrimaryCommandBuffer, SecondaryCommandBuffer { 79 this(VkCommandBuffer vkObj, VulkanCommandPool pool, CommandBufferLevel level) { 80 _vkObj = vkObj; 81 _pool = pool; 82 _vk = pool.vk; 83 _level = level; 84 } 85 86 @property VkCommandBuffer vkObj() { 87 return _vkObj; 88 } 89 90 override @property CommandPool pool() { 91 return _pool; 92 } 93 94 override @property CommandBufferLevel level() const { 95 return _level; 96 } 97 98 @property VkDeviceCmds vk() { 99 return _vk; 100 } 101 102 override void reset() { 103 vulkanEnforce(vk.ResetCommandBuffer(vkObj, 0), "Could not reset vulkan command buffer"); 104 } 105 106 override void begin(in CommandBufferUsage usage) { 107 VkCommandBufferInheritanceInfo cbii; 108 VkCommandBufferBeginInfo cbbi; 109 cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 110 cbbi.flags = cast(VkCommandBufferUsageFlags) usage; 111 if (_level == CommandBufferLevel.secondary) { 112 cbii.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; 113 cbbi.pInheritanceInfo = &cbii; 114 } 115 vulkanEnforce(vk.BeginCommandBuffer(vkObj, &cbbi), "Could not begin vulkan command buffer"); 116 } 117 118 override void beginWithinRenderPass(in CommandBufferUsage usage, 119 RenderPass rp, Framebuffer fb, uint subpass) { 120 import gfx.core.util : unsafeCast; 121 122 assert(_level == CommandBufferLevel.secondary); 123 VkCommandBufferInheritanceInfo cbii; 124 cbii.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; 125 if (rp) { 126 cbii.renderPass = rp.unsafeCast!VulkanRenderPass().vkObj; 127 } 128 if (fb) { 129 cbii.framebuffer = fb.unsafeCast!VulkanFramebuffer().vkObj; 130 } 131 cbii.subpass = subpass; 132 133 VkCommandBufferBeginInfo cbbi; 134 cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 135 cbbi.flags = cast(VkCommandBufferUsageFlags) usage; 136 cbbi.pInheritanceInfo = &cbii; 137 vulkanEnforce(vk.BeginCommandBuffer(vkObj, &cbbi), "Could not begin vulkan command buffer"); 138 } 139 140 override void end() { 141 vulkanEnforce(vk.EndCommandBuffer(vkObj), "Could not end vulkan command buffer"); 142 } 143 144 override void pipelineBarrier(Trans!PipelineStage stageTrans, 145 BufferMemoryBarrier[] bufMbs, ImageMemoryBarrier[] imgMbs) { 146 import std.algorithm : map; 147 import std.array : array; 148 149 auto vkBufMbs = bufMbs.map!((BufferMemoryBarrier bufMb) { 150 VkBufferMemoryBarrier vkBufMb; 151 vkBufMb.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 152 vkBufMb.srcAccessMask = accessToVk(bufMb.accessMaskTrans.from); 153 vkBufMb.dstAccessMask = accessToVk(bufMb.accessMaskTrans.to); 154 vkBufMb.srcQueueFamilyIndex = bufMb.queueFamIndexTrans.from; 155 vkBufMb.dstQueueFamilyIndex = bufMb.queueFamIndexTrans.to; 156 vkBufMb.buffer = enforce(cast(VulkanBuffer) bufMb.buffer, 157 "Did not pass a Vulkan buffer").vkObj; 158 vkBufMb.offset = bufMb.offset; 159 vkBufMb.size = bufMb.size; 160 return vkBufMb; 161 }).array; 162 163 auto vkImgMbs = imgMbs.map!((ImageMemoryBarrier imgMb) { 164 VkImageMemoryBarrier vkImgMb; 165 vkImgMb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 166 vkImgMb.srcAccessMask = accessToVk(imgMb.accessMaskTrans.from); 167 vkImgMb.dstAccessMask = accessToVk(imgMb.accessMaskTrans.to); 168 vkImgMb.oldLayout = imgMb.layoutTrans.from.toVk(); 169 vkImgMb.newLayout = imgMb.layoutTrans.to.toVk(); 170 vkImgMb.srcQueueFamilyIndex = imgMb.queueFamIndexTrans.from; 171 vkImgMb.dstQueueFamilyIndex = imgMb.queueFamIndexTrans.to; 172 vkImgMb.image = enforce(cast(VulkanImageBase) imgMb.image, 173 "Did not pass a Vulkan image").vkObj; 174 vkImgMb.subresourceRange = imgMb.range.toVk(); 175 return vkImgMb; 176 }).array; 177 178 vk.CmdPipelineBarrier(vkObj, pipelineStageToVk(stageTrans.from), 179 pipelineStageToVk(stageTrans.to), 0, 0, null, cast(uint) vkBufMbs.length, 180 vkBufMbs.ptr, cast(uint) vkImgMbs.length, vkImgMbs.ptr); 181 } 182 183 override void clearColorImage(ImageBase image, ImageLayout layout, 184 in ClearColorValues clearValues, ImageSubresourceRange[] ranges) { 185 import std.algorithm : map; 186 import std.array : array; 187 188 auto vkImg = enforce(cast(VulkanImageBase) image, "Did not pass a vulkan image").vkObj; 189 auto vkLayout = layout.toVk(); 190 auto vkClear = cast(const(VkClearColorValue)*) cast(const(void)*)&clearValues.values; 191 auto vkRanges = ranges.map!(r => r.toVk()).array; 192 193 vk.CmdClearColorImage(vkObj, vkImg, vkLayout, vkClear, 194 cast(uint) vkRanges.length, &vkRanges[0]); 195 } 196 197 override void clearDepthStencilImage(ImageBase image, ImageLayout layout, 198 in ClearDepthStencilValues clearValues, ImageSubresourceRange[] ranges) { 199 import std.algorithm : map; 200 import std.array : array; 201 202 auto vkImg = enforce(cast(VulkanImageBase) image, "Did not pass a vulkan image").vkObj; 203 auto vkLayout = layout.toVk(); 204 auto vkClear = VkClearDepthStencilValue(clearValues.depth, clearValues.stencil); 205 auto vkRanges = ranges.map!(r => r.toVk()).array; 206 207 vk.CmdClearDepthStencilImage(vkObj, vkImg, vkLayout, &vkClear, 208 cast(uint) vkRanges.length, &vkRanges[0]); 209 } 210 211 override void fillBuffer(Buffer dst, in size_t offset, in size_t size, uint value) { 212 auto vkBuf = enforce(cast(VulkanBuffer) dst, 213 "Did not pass a valid vulkan buffer to fillBuffer").vkObj; 214 vk.CmdFillBuffer(vkObj, vkBuf, offset, size, value); 215 } 216 217 override void updateBuffer(Buffer dst, in size_t offset, in uint[] data) { 218 auto vkBuf = enforce(cast(VulkanBuffer) dst, 219 "Did not pass a valid vulkan buffer to updateBuffer").vkObj; 220 vk.CmdUpdateBuffer(vkObj, vkBuf, offset, 4 * data.length, cast(void*) data.ptr); 221 } 222 223 override void copyBuffer(Trans!Buffer buffers, in CopyRegion[] regions) { 224 import std.algorithm : map; 225 import std.array : array; 226 227 auto vkRegions = regions.map!(r => VkBufferCopy(r.offset.from, r.offset.to, r.size)).array; 228 229 vk.CmdCopyBuffer(vkObj, enforce(cast(VulkanBuffer) buffers.from).vkObj, 230 enforce(cast(VulkanBuffer) buffers.to).vkObj, 231 cast(uint) vkRegions.length, vkRegions.ptr); 232 } 233 234 override void copyBufferToImage(Buffer srcBuffer, ImageBase dstImage, 235 in ImageLayout dstLayout, in BufferImageCopy[] regions) { 236 import gfx.core.util : transmute; 237 import std.algorithm : map; 238 import std.array : array; 239 240 auto vkRegions = regions.map!(bic => transmute!VkBufferImageCopy(bic)).array; 241 242 vk.CmdCopyBufferToImage(vkObj, enforce(cast(VulkanBuffer) srcBuffer) 243 .vkObj, enforce(cast(VulkanImageBase) dstImage).vkObj, 244 dstLayout.toVk(), cast(uint) vkRegions.length, vkRegions.ptr); 245 } 246 247 override void setViewport(in uint firstViewport, in Viewport[] viewports) { 248 import gfx.core.util : transmute; 249 250 const vkVp = transmute!(const(VkViewport)[])(viewports); 251 vk.CmdSetViewport(vkObj, firstViewport, cast(uint) vkVp.length, vkVp.ptr); 252 } 253 254 override void setScissor(in uint firstScissor, in Rect[] scissors) { 255 import gfx.core.util : transmute; 256 257 const vkSc = transmute!(const(VkRect2D)[])(scissors); 258 vk.CmdSetScissor(vkObj, firstScissor, cast(uint) vkSc.length, vkSc.ptr); 259 } 260 261 override void setDepthBounds(in float minDepth, in float maxDepth) { 262 vk.CmdSetDepthBounds(vkObj, minDepth, maxDepth); 263 } 264 265 override void setLineWidth(in float lineWidth) { 266 vk.CmdSetLineWidth(vkObj, lineWidth); 267 } 268 269 override void setDepthBias(in float constFactor, in float clamp, in float slopeFactor) { 270 vk.CmdSetDepthBias(vkObj, constFactor, clamp, slopeFactor); 271 } 272 273 override void setStencilCompareMask(in StencilFace faceMask, in uint compareMask) { 274 vk.CmdSetStencilCompareMask(vkObj, cast(VkStencilFaceFlags) faceMask, compareMask); 275 } 276 277 override void setStencilWriteMask(in StencilFace faceMask, in uint writeMask) { 278 vk.CmdSetStencilWriteMask(vkObj, cast(VkStencilFaceFlags) faceMask, writeMask); 279 } 280 281 override void setStencilReference(in StencilFace faceMask, in uint reference) { 282 vk.CmdSetStencilReference(vkObj, cast(VkStencilFaceFlags) faceMask, reference); 283 } 284 285 override void setBlendConstants(in float[4] blendConstants) { 286 vk.CmdSetBlendConstants(vkObj, blendConstants); 287 } 288 289 override void beginRenderPass(RenderPass rp, Framebuffer fb, in Rect area, 290 in ClearValues[] clearValues) { 291 import std.algorithm : map; 292 import std.array : array; 293 294 assert(_level == CommandBufferLevel.primary); 295 296 auto vkCvs = clearValues.map!((ClearValues cv) { 297 VkClearValue vkCv; 298 if (cv.type == ClearValues.Type.color) { 299 const ccv = cv.values.color; 300 VkClearColorValue vkCcv; 301 switch (ccv.type) { 302 case ClearColorValues.Type.f32: 303 vkCcv.float32 = ccv.values.f32; 304 break; 305 case ClearColorValues.Type.i32: 306 vkCcv.int32 = ccv.values.i32; 307 break; 308 case ClearColorValues.Type.u32: 309 vkCcv.uint32 = ccv.values.u32; 310 break; 311 default: 312 break; 313 } 314 vkCv.color = vkCcv; 315 } else if (cv.type == ClearValues.Type.depthStencil) { 316 const dscv = cv.values.depthStencil; 317 vkCv.depthStencil = VkClearDepthStencilValue(dscv.depth, dscv.stencil); 318 } 319 return vkCv; 320 }).array; 321 322 VkRenderPassBeginInfo bi; 323 bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 324 bi.renderPass = enforce(cast(VulkanRenderPass) rp, 325 "did not supply a valid Vulkan render pass").vkObj; 326 bi.framebuffer = enforce(cast(VulkanFramebuffer) fb, 327 "did not supply a valid Vulkan frame buffer").vkObj; 328 bi.renderArea = area.toVk(); 329 bi.clearValueCount = cast(uint) vkCvs.length; 330 bi.pClearValues = vkCvs.ptr; 331 332 vk.CmdBeginRenderPass(vkObj, &bi, VK_SUBPASS_CONTENTS_INLINE); 333 } 334 335 override void nextSubpass() { 336 assert(_level == CommandBufferLevel.primary); 337 vk.CmdNextSubpass(vkObj, VK_SUBPASS_CONTENTS_INLINE); 338 } 339 340 override void endRenderPass() { 341 assert(_level == CommandBufferLevel.primary); 342 vk.CmdEndRenderPass(vkObj); 343 } 344 345 override void bindPipeline(Pipeline pipeline) { 346 vk.CmdBindPipeline(vkObj, VK_PIPELINE_BIND_POINT_GRAPHICS, 347 enforce(cast(VulkanPipeline) pipeline, "did not pass a valid Vulkan pipeline") 348 .vkObj); 349 } 350 351 override void bindVertexBuffers(uint firstBinding, VertexBinding[] bindings) { 352 import std.algorithm : map; 353 import std.array : array; 354 355 auto vkBufs = bindings.map!(b => enforce(cast(VulkanBuffer) b.buffer).vkObj).array; 356 auto vkOffsets = bindings.map!(b => cast(VkDeviceSize) b.offset).array; 357 vk.CmdBindVertexBuffers(vkObj, firstBinding, cast(uint) bindings.length, 358 vkBufs.ptr, vkOffsets.ptr); 359 } 360 361 override void bindIndexBuffer(Buffer indexBuf, size_t offset, IndexType type) { 362 auto vkBuf = enforce(cast(VulkanBuffer) indexBuf).vkObj; 363 vk.CmdBindIndexBuffer(vkObj, vkBuf, offset, type.toVk()); 364 } 365 366 override void bindDescriptorSets(PipelineBindPoint bindPoint, PipelineLayout layout, 367 uint firstSet, DescriptorSet[] sets, in size_t[] dynamicOffsets) { 368 import std.algorithm : map; 369 import std.array : array; 370 371 auto vkSets = sets.map!(s => enforce(cast(VulkanDescriptorSet) s).vkObj).array; 372 static if (size_t.sizeof == uint.sizeof) { 373 const vkOffsets = dynamicOffsets; 374 } else { 375 const vkOffsets = dynamicOffsets.map!(o => cast(uint) o).array; 376 } 377 378 vk.CmdBindDescriptorSets(vkObj, bindPoint.toVk(), 379 enforce(cast(VulkanPipelineLayout) layout).vkObj, firstSet, 380 cast(uint) vkSets.length, vkSets.ptr, cast(uint) vkOffsets.length, vkOffsets.ptr); 381 } 382 383 override void pushConstants(PipelineLayout layout, ShaderStage stages, 384 size_t offset, size_t size, const(void)* data) { 385 auto vkPl = enforce(cast(VulkanPipelineLayout) layout).vkObj; 386 vk.CmdPushConstants(vkObj, vkPl, shaderStageToVk(stages), 387 cast(uint) offset, cast(uint) size, data); 388 } 389 390 override void draw(uint vertexCount, uint instanceCount, uint firstVertex, uint firstInstance) { 391 vk.CmdDraw(vkObj, vertexCount, instanceCount, firstVertex, firstInstance); 392 } 393 394 override void drawIndexed(uint indexCount, uint instanceCount, 395 uint firstVertex, int vertexOffset, uint firstInstance) { 396 vk.CmdDrawIndexed(vkObj, indexCount, instanceCount, firstVertex, 397 vertexOffset, firstInstance); 398 } 399 400 override void execute(SecondaryCommandBuffer[] buffers) { 401 import gfx.core.util : unsafeCast; 402 import std.algorithm : map; 403 import std.array : array; 404 405 auto vkBufs = buffers.map!(b => b.unsafeCast!VulkanCommandBuffer().vkObj).array; 406 vk.CmdExecuteCommands(vkObj, cast(uint)vkBufs.length, vkBufs.ptr); 407 } 408 409 private VkCommandBuffer _vkObj; 410 private VulkanCommandPool _pool; 411 private VkDeviceCmds _vk; 412 private CommandBufferLevel _level; 413 }