changeset 1497:56aa8fe70e9e default tip

add: super suboptimal implementation to support per-frame descriptor sets
author sam <sam@basx.dev>
date Wed, 24 Sep 2025 23:55:36 +0700
parents 0615cd5bfd97
children
files semicongine/core/types.nim semicongine/fonts.nim semicongine/rendering/memory.nim semicongine/rendering/renderer.nim
diffstat 4 files changed, 93 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/semicongine/core/types.nim	Wed Sep 24 22:17:43 2025 +0700
+++ b/semicongine/core/types.nim	Wed Sep 24 23:55:36 2025 +0700
@@ -101,7 +101,7 @@
 
   # shader related types
   DescriptorSetData*[T: object] = object
-    data*: T
+    data*: array[INFLIGHTFRAMES.int, T]
     vk*: array[INFLIGHTFRAMES.int, VkDescriptorSet]
 
   Pipeline*[TShader] = object
--- a/semicongine/fonts.nim	Wed Sep 24 22:17:43 2025 +0700
+++ b/semicongine/fonts.nim	Wed Sep 24 23:55:36 2025 +0700
@@ -147,7 +147,8 @@
 
   # generate glyph atlas from bitmaps
   let packed = pack(bitmaps)
-  result.descriptorSet.data.fontAtlas = packed.atlas
+  for i in 0 ..< INFLIGHTFRAMES:
+    result.descriptorSet.data[i].fontAtlas = packed.atlas
 
   # generate quad-information for use in shader
   for i in 0 ..< codePoints.len:
@@ -161,8 +162,8 @@
     result.advance[codePoint] = advanceUnscaled.float32 * glyph2QuadScale
 
     let
-      atlasW = float32(result.descriptorSet.data.fontAtlas.width)
-      atlasH = float32(result.descriptorSet.data.fontAtlas.height)
+      atlasW = float32(result.descriptorSet.data[0].fontAtlas.width)
+      atlasH = float32(result.descriptorSet.data[0].fontAtlas.height)
       uv = vec2(packed.coords[i].x, packed.coords[i].y)
       bitmapW = float32(bitmaps[i].width)
       bitmapH = float32(bitmaps[i].height)
@@ -173,16 +174,17 @@
       top = -offsetY[codePoint].float32 / lineHeightPixels
       bottom = top - bitmapH / lineHeightPixels
 
-    template glyphquads(): untyped =
-      result.descriptorSet.data.glyphquads.data
+    template glyphquads_t(j: int): untyped =
+      result.descriptorSet.data[j].glyphquads.data
 
-    glyphquads.pos[i] = vec4(left, bottom, right, top)
-    glyphquads.uv[i] = vec4(
-      (uv.x + 0.5) / atlasW, # left
-      (uv.y + bitmapH - 0.5) / atlasH, # bottom
-      (uv.x + bitmapW - 0.5) / atlasW, # right
-      (uv.y + 0.5) / atlasH, # top
-    )
+    for k in 0 ..< INFLIGHTFRAMES.int:
+      glyphquads_t(k).pos[i] = vec4(left, bottom, right, top)
+      glyphquads_t(k).uv[i] = vec4(
+        (uv.x + 0.5) / atlasW, # left
+        (uv.y + bitmapH - 0.5) / atlasH, # bottom
+        (uv.x + bitmapW - 0.5) / atlasW, # right
+        (uv.y + 0.5) / atlasH, # top
+      )
     if i == 0:
       result.fallbackCharacter = codePoint
     result.descriptorGlyphIndex[codePoint] = i.uint16
--- a/semicongine/rendering/memory.nim	Wed Sep 24 22:17:43 2025 +0700
+++ b/semicongine/rendering/memory.nim	Wed Sep 24 23:55:36 2025 +0700
@@ -119,7 +119,7 @@
     descriptorSet: DescriptorSetData,
 ) =
   # santization checks
-  for theName, value in descriptorSet.data.fieldPairs:
+  for theName, value in descriptorSet.data[0].fieldPairs:
     when typeof(value) is GPUValue:
       assert value.buffer.vk.Valid,
         "Invalid buffer, did you call 'assignBuffers' for this buffer?"
@@ -159,85 +159,80 @@
   var imageWrites = newSeqOfCap[VkDescriptorImageInfo](1024)
   var bufferWrites = newSeqOfCap[VkDescriptorBufferInfo](1024)
 
-  for theFieldname, fieldvalue in fieldPairs(descriptorSet.data):
-    const descriptorType = getDescriptorType[typeof(fieldvalue)]()
-    const descriptorCount = getDescriptorCount[typeof(fieldvalue)]()
-    const descriptorBindingNumber =
-      getBindingNumber[typeof(descriptorSet.data)](theFieldname)
-    for i in 0 ..< descriptorSet.vk.len:
-      when typeof(fieldvalue) is GPUValue:
-        bufferWrites.add VkDescriptorBufferInfo(
-          buffer: fieldvalue.buffer.vk,
-          offset: fieldvalue.offset,
-          range: fieldvalue.size,
-        )
-        descriptorSetWrites.add VkWriteDescriptorSet(
-          sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
-          dstSet: descriptorSet.vk[i],
-          dstBinding: descriptorBindingNumber,
-          dstArrayElement: 0,
-          descriptorType: descriptorType,
-          descriptorCount: descriptorCount,
-          pImageInfo: nil,
-          pBufferInfo: addr(bufferWrites[^1]),
-        )
-      elif typeof(fieldvalue) is ImageObject:
-        imageWrites.add VkDescriptorImageInfo(
-          sampler: fieldvalue.sampler,
-          imageView: fieldvalue.imageView,
-          imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
-        )
-        descriptorSetWrites.add VkWriteDescriptorSet(
-          sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
-          dstSet: descriptorSet.vk[i],
-          dstBinding: descriptorBindingNumber,
-          dstArrayElement: 0,
-          descriptorType: descriptorType,
-          descriptorCount: descriptorCount,
-          pImageInfo: addr(imageWrites[^1]),
-          pBufferInfo: nil,
-        )
-      elif typeof(fieldvalue) is array:
-        when elementType(fieldvalue) is ImageObject:
-          for image in fieldvalue.litems:
-            imageWrites.add VkDescriptorImageInfo(
-              sampler: image.sampler,
-              imageView: image.imageView,
-              imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
-            )
+  for fI in 0 ..< INFLIGHTFRAMES:
+    for theFieldname, fieldvalue in fieldPairs(descriptorSet.data[fI]):
+        const descriptorType = getDescriptorType[typeof(fieldvalue)]()
+        const descriptorCount = getDescriptorCount[typeof(fieldvalue)]()
+        const descriptorBindingNumber = getBindingNumber[typeof(descriptorSet.data[fI])](theFieldname)
+        when typeof(fieldvalue) is GPUValue:
+          bufferWrites.add VkDescriptorBufferInfo(
+            buffer: fieldvalue.buffer.vk,
+            offset: fieldvalue.offset,
+            range: fieldvalue.size,
+          )
           descriptorSetWrites.add VkWriteDescriptorSet(
             sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
-            dstSet: descriptorSet.vk[i],
-            dstBinding: descriptorBindingNumber,
-            dstArrayElement: 0,
-            descriptorType: descriptorType,
-            descriptorCount: descriptorCount,
-            pImageInfo: addr(imageWrites[^descriptorCount.int]),
-            pBufferInfo: nil,
-          )
-        elif elementType(fieldvalue) is GPUValue:
-          for entry in fieldvalue.litems:
-            bufferWrites.add VkDescriptorBufferInfo(
-              buffer: entry.buffer.vk, offset: entry.offset, range: entry.size
-            )
-          descriptorSetWrites.add VkWriteDescriptorSet(
-            sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
-            dstSet: descriptorSet.vk[i],
+            dstSet: descriptorSet.vk[fI],
             dstBinding: descriptorBindingNumber,
             dstArrayElement: 0,
             descriptorType: descriptorType,
             descriptorCount: descriptorCount,
             pImageInfo: nil,
-            pBufferInfo: addr(bufferWrites[^descriptorCount.int]),
+            pBufferInfo: addr(bufferWrites[^1]),
+          )
+        elif typeof(fieldvalue) is ImageObject:
+          imageWrites.add VkDescriptorImageInfo(
+            sampler: fieldvalue.sampler,
+            imageView: fieldvalue.imageView,
+            imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+          )
+          descriptorSetWrites.add VkWriteDescriptorSet(
+            sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+            dstSet: descriptorSet.vk[fI],
+            dstBinding: descriptorBindingNumber,
+            dstArrayElement: 0,
+            descriptorType: descriptorType,
+            descriptorCount: descriptorCount,
+            pImageInfo: addr(imageWrites[^1]),
+            pBufferInfo: nil,
           )
+        elif typeof(fieldvalue) is array:
+          when elementType(fieldvalue) is ImageObject:
+            for image in fieldvalue.litems:
+              imageWrites.add VkDescriptorImageInfo(
+                sampler: image.sampler,
+                imageView: image.imageView,
+                imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+              )
+            descriptorSetWrites.add VkWriteDescriptorSet(
+              sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+              dstSet: descriptorSet.vk[fI],
+              dstBinding: descriptorBindingNumber,
+              dstArrayElement: 0,
+              descriptorType: descriptorType,
+              descriptorCount: descriptorCount,
+              pImageInfo: addr(imageWrites[^descriptorCount.int]),
+              pBufferInfo: nil,
+            )
+          elif elementType(fieldvalue) is GPUValue:
+            for entry in fieldvalue.litems:
+              bufferWrites.add VkDescriptorBufferInfo(
+                buffer: entry.buffer.vk, offset: entry.offset, range: entry.size
+              )
+            descriptorSetWrites.add VkWriteDescriptorSet(
+              sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+              dstSet: descriptorSet.vk[fI],
+              dstBinding: descriptorBindingNumber,
+              dstArrayElement: 0,
+              descriptorType: descriptorType,
+              descriptorCount: descriptorCount,
+              pImageInfo: nil,
+              pBufferInfo: addr(bufferWrites[^descriptorCount.int]),
+            )
+          else:
+            {.error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue)).}
         else:
-          {.
-            error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue))
-          .}
-      else:
-        {.
-          error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue))
-        .}
+          {.error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue)).}
 
   vkUpdateDescriptorSets(
     device = engine().vulkan.device,
@@ -402,7 +397,8 @@
       (value.buffer, value.offset) =
         allocateGPUData(renderdata, value.bufferType, value.size)
     elif typeof(value) is DescriptorSetData:
-      assignBuffers(renderdata, value.data, uploadData = uploadData)
+      for i in 0 ..< INFLIGHTFRAMES:
+        assignBuffers(renderdata, value.data[i], uploadData = uploadData)
     elif typeof(value) is array:
       when elementType(value) is GPUValue:
         for v in value.mitems:
@@ -414,7 +410,8 @@
 proc assignBuffers*(
     renderdata: var RenderData, descriptorSet: var DescriptorSetData, uploadData = true
 ) =
-  assignBuffers(renderdata, descriptorSet.data, uploadData = uploadData)
+  for i in 0 ..< INFLIGHTFRAMES:
+    assignBuffers(renderdata, descriptorSet.data[i], uploadData = uploadData)
 
 proc asGPUArray*[T](data: sink openArray[T], bufferType: static BufferType): auto =
   GPUArray[T, bufferType](data: @data)
--- a/semicongine/rendering/renderer.nim	Wed Sep 24 22:17:43 2025 +0700
+++ b/semicongine/rendering/renderer.nim	Wed Sep 24 23:55:36 2025 +0700
@@ -191,13 +191,14 @@
   )
 
 proc uploadImages*(renderdata: var RenderData, descriptorSet: var DescriptorSetData) =
-  for name, value in fieldPairs(descriptorSet.data):
-    when typeof(value) is ImageObject:
-      renderdata.createVulkanImage(value)
-    elif typeof(value) is array:
-      when elementType(value) is ImageObject:
-        for image in value.mitems:
-          renderdata.createVulkanImage(image)
+  for i in 0 ..< INFLIGHTFRAMES:
+    for name, value in fieldPairs(descriptorSet.data[i]):
+      when typeof(value) is ImageObject:
+        renderdata.createVulkanImage(value)
+      elif typeof(value) is array:
+        when elementType(value) is ImageObject:
+          for image in value.mitems:
+            renderdata.createVulkanImage(image)
 
 type EMPTY = object # only used for static assertions