view semicongine/vulkan/commandbuffer.nim @ 950:fe48b091e83f

did: tons of small improvments, on the way to make GPU sync (more) correct I guess
author sam <sam@basx.dev>
date Sun, 31 Mar 2024 22:11:50 +0700
parents b65068f5f246
children c6213a794ab0
line wrap: on
line source

import std/strformat

import ../core
import ./device
import ./physicaldevice

type
  CommandBufferPool* = object
    device: Device
    vk*: VkCommandPool
    family*: QueueFamily
    buffers*: seq[VkCommandBuffer]

proc createCommandBufferPool*(device: Device, family: QueueFamily, nBuffers: int): CommandBufferPool =
  assert device.vk.valid
  var createInfo = VkCommandPoolCreateInfo(
    sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
    flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT],
    queueFamilyIndex: family.index,
  )
  result.family = family
  result.device = device
  checkVkResult device.vk.vkCreateCommandPool(addr createInfo, nil, addr result.vk)

  var allocInfo = VkCommandBufferAllocateInfo(
    sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
    commandPool: result.vk,
    level: VK_COMMAND_BUFFER_LEVEL_PRIMARY,
    commandBufferCount: uint32(nBuffers),
  )
  result.buffers = newSeq[VkCommandBuffer](nBuffers)
  checkVkResult device.vk.vkAllocateCommandBuffers(addr allocInfo, result.buffers.toCPointer)

proc pipelineBarrier*(
  commandBuffer: VkCommandBuffer,
  srcStages: openArray[VkPipelineStageFlagBits],
  dstStages: openArray[VkPipelineStageFlagBits],
  memoryBarriers: openArray[VkMemoryBarrier] = [],
  bufferMemoryBarriers: openArray[VkBufferMemoryBarrier] = [],
  imageBarriers: openArray[VkImageMemoryBarrier] = [],
) =

  vkCmdPipelineBarrier(
    commandBuffer,
    srcStageMask = srcStages.toBits,
    dstStageMask = dstStages.toBits,
    dependencyFlags = VkDependencyFlags(0),
    memoryBarrierCount = uint32(memoryBarriers.len),
    pMemoryBarriers = memoryBarriers.toCPointer,
    bufferMemoryBarrierCount = uint32(bufferMemoryBarriers.len),
    pBufferMemoryBarriers = bufferMemoryBarriers.toCPointer,
    imageMemoryBarrierCount = uint32(imageBarriers.len),
    pImageMemoryBarriers = imageBarriers.toCPointer,
  )


template withSingleUseCommandBuffer*(device: Device, queue: Queue, needsTransfer: bool, commandBuffer, body: untyped): untyped =
  # TODO? This is super slow, because we call vkQueueWaitIdle
  assert device.vk.valid
  assert queue.vk.valid

  var
    commandBufferPool = createCommandBufferPool(device, queue.family, 1)
    commandBuffer = commandBufferPool.buffers[0]
    beginInfo = VkCommandBufferBeginInfo(
      sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
      flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT),
    )
  checkVkResult commandBuffer.vkBeginCommandBuffer(addr beginInfo)

  block:
    body

  checkVkResult commandBuffer.vkEndCommandBuffer()
  var submitInfo = VkSubmitInfo(
    sType: VK_STRUCTURE_TYPE_SUBMIT_INFO,
    commandBufferCount: 1,
    pCommandBuffers: addr commandBuffer,
  )
  checkVkResult queue.vk.vkQueueSubmit(1, addr submitInfo, VkFence(0))
  checkVkResult queue.vk.vkQueueWaitIdle()
  commandBufferPool.destroy()

proc destroy*(commandpool: var CommandBufferPool) =
  assert commandpool.device.vk.valid
  assert commandpool.vk.valid
  commandpool.device.vk.vkDestroyCommandPool(commandpool.vk, nil)
  commandpool.vk.reset