diff semicongine/vulkan/descriptor.nim @ 840:44ec744fbedc

did: package restructuring according to nimble recommendation for libraries
author Sam <sam@basx.dev>
date Sat, 02 Dec 2023 22:23:29 +0700
parents
children 904e0a827ef3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/semicongine/vulkan/descriptor.nim	Sat Dec 02 22:23:29 2023 +0700
@@ -0,0 +1,175 @@
+import std/enumerate
+import std/tables
+
+import ../core
+import ./device
+import ./buffer
+import ./image
+
+type
+  DescriptorType* = enum
+    Uniform, ImageSampler
+  Descriptor* = object # "fields" of a DescriptorSetLayout
+    name*: string
+    count*: int
+    stages*: seq[VkShaderStageFlagBits]
+    case thetype*: DescriptorType
+    of Uniform:
+      buffer*: Buffer
+      offset*: int
+      size*: int
+    of ImageSampler:
+      imageviews*: seq[ImageView]
+      samplers*: seq[VulkanSampler]
+  DescriptorSet* = object # "instance" of a DescriptorSetLayout
+    vk*: VkDescriptorSet
+    layout*: DescriptorSetLayout
+  DescriptorSetLayout* = object # "type-description" of a DescriptorSet
+    device: Device
+    vk*: VkDescriptorSetLayout
+    descriptors*: seq[Descriptor]
+  DescriptorPool* = object # required for allocation of DescriptorSet
+    device: Device
+    vk*: VkDescriptorPool
+    maxSets*: int # maximum number of allocatable descriptor sets
+    counts*: seq[(VkDescriptorType, int)] # maximum number for each descriptor type to allocate
+
+const DESCRIPTOR_TYPE_MAP = {
+  Uniform: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+  ImageSampler: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+}.toTable
+
+func vkType(descriptor: Descriptor): VkDescriptorType =
+  DESCRIPTOR_TYPE_MAP[descriptor.thetype]
+
+proc createDescriptorSetLayout*(device: Device, descriptors: seq[Descriptor]): DescriptorSetLayout =
+  assert device.vk.valid
+
+  result.device = device
+  result.descriptors = descriptors
+
+  var layoutbindings: seq[VkDescriptorSetLayoutBinding]
+  for i, descriptor in enumerate(descriptors):
+    layoutbindings.add VkDescriptorSetLayoutBinding(
+      binding: uint32(i),
+      descriptorType: descriptor.vkType,
+      descriptorCount: uint32(descriptor.count),
+      stageFlags: toBits descriptor.stages,
+      pImmutableSamplers: nil,
+    )
+  var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo(
+    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+    bindingCount: uint32(layoutbindings.len),
+    pBindings: layoutbindings.toCPointer
+  )
+  checkVkResult vkCreateDescriptorSetLayout(device.vk, addr(layoutCreateInfo), nil, addr(result.vk))
+
+proc destroy*(descriptorSetLayout: var DescriptorSetLayout) =
+  assert descriptorSetLayout.device.vk.valid
+  assert descriptorSetLayout.vk.valid
+  descriptorSetLayout.device.vk.vkDestroyDescriptorSetLayout(descriptorSetLayout.vk, nil)
+  descriptorSetLayout.vk.reset
+
+
+proc createDescriptorSetPool*(device: Device, counts: seq[(VkDescriptorType, int)], maxSets = 1000): DescriptorPool =
+  assert device.vk.valid
+
+  result.device = device
+  result.maxSets = maxSets
+  result.counts = counts
+
+  var poolSizes: seq[VkDescriptorPoolSize]
+  for (thetype, count) in result.counts:
+    poolSizes.add VkDescriptorPoolSize(thetype: thetype, descriptorCount: uint32(count))
+  var poolInfo = VkDescriptorPoolCreateInfo(
+    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+    poolSizeCount: uint32(poolSizes.len),
+    pPoolSizes: poolSizes.toCPointer,
+    maxSets: uint32(result.maxSets),
+  )
+  checkVkResult vkCreateDescriptorPool(result.device.vk, addr(poolInfo), nil, addr(result.vk))
+
+proc reset*(pool: DescriptorPool) =
+  assert pool.device.vk.valid
+  assert pool.vk.valid
+  checkVkResult vkResetDescriptorPool(pool.device.vk, pool.vk, VkDescriptorPoolResetFlags(0))
+
+proc destroy*(pool: var DescriptorPool) =
+  assert pool.device.vk.valid
+  assert pool.vk.valid
+  pool.device.vk.vkDestroyDescriptorPool(pool.vk, nil)
+  pool.vk.reset
+
+proc allocateDescriptorSet*(pool: DescriptorPool, layout: DescriptorSetLayout, nframes: int): seq[DescriptorSet] =
+  assert pool.device.vk.valid
+  assert pool.vk.valid
+  assert layout.device.vk.valid
+  assert layout.vk.valid
+
+  var layouts: seq[VkDescriptorSetLayout]
+  var descriptorSets = newSeq[VkDescriptorSet](nframes)
+  for i in 0 ..< nframes:
+    layouts.add layout.vk
+  var allocInfo = VkDescriptorSetAllocateInfo(
+    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+    descriptorPool: pool.vk,
+    descriptorSetCount: uint32(layouts.len),
+    pSetLayouts: layouts.toCPointer,
+  )
+
+  checkVkResult vkAllocateDescriptorSets(pool.device.vk, addr(allocInfo), descriptorSets.toCPointer)
+  for descriptorSet in descriptorSets:
+    result.add DescriptorSet(vk: descriptorSet, layout: layout)
+
+proc writeDescriptorSet*(descriptorSet: DescriptorSet, bindingBase=0'u32) =
+  # assumes descriptors of the descriptorSet are arranged interleaved in buffer
+  assert descriptorSet.layout.device.vk.valid
+  assert descriptorSet.layout.vk.valid
+  assert descriptorSet.vk.valid
+
+  var descriptorSetWrites: seq[VkWriteDescriptorSet]
+  var bufferInfos: seq[VkDescriptorBufferInfo]
+
+  var i = bindingBase
+  # need to keep this sequence out of the loop, otherwise it will be 
+  # gc-ed before the final update call and pointers are invalid :(
+  var imgInfos: seq[seq[VkDescriptorImageInfo]]
+  for descriptor in descriptorSet.layout.descriptors:
+    if descriptor.thetype == Uniform:
+      assert descriptor.buffer.vk.valid
+      bufferInfos.add VkDescriptorBufferInfo(
+        buffer: descriptor.buffer.vk,
+        offset: uint64(descriptor.offset),
+        range: uint64(descriptor.size),
+      )
+      descriptorSetWrites.add VkWriteDescriptorSet(
+          sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+          dstSet: descriptorSet.vk,
+          dstBinding: i,
+          dstArrayElement: 0,
+          descriptorType: descriptor.vkType,
+          descriptorCount: uint32(descriptor.count),
+          pBufferInfo: addr bufferInfos[^1],
+        )
+    elif descriptor.thetype == ImageSampler:
+      var imgInfo: seq[VkDescriptorImageInfo]
+      for img_i in 0 ..< descriptor.count:
+        assert descriptor.imageviews[img_i].vk.valid
+        assert descriptor.samplers[img_i].vk.valid
+        imgInfo.add VkDescriptorImageInfo(
+          imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+          imageView: descriptor.imageviews[img_i].vk,
+          sampler: descriptor.samplers[img_i].vk,
+        )
+      imgInfos.add imgInfo
+      descriptorSetWrites.add VkWriteDescriptorSet(
+          sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+          dstSet: descriptorSet.vk,
+          dstBinding: i,
+          dstArrayElement: 0,
+          descriptorType: descriptor.vkType,
+          descriptorCount: uint32(descriptor.count),
+          pImageInfo: imgInfos[^1].toCPointer,
+        )
+    inc i
+  descriptorSet.layout.device.vk.vkUpdateDescriptorSets(uint32(descriptorSetWrites.len), descriptorSetWrites.toCPointer, 0, nil)