changeset 1373:19469f21f34e

did: implement vecs as distinct types
author sam <sam@basx.dev>
date Fri, 06 Dec 2024 22:20:39 +0700
parents 2da623ec519b
children 92c089136a05
files semicongine/contrib/algorithms/texture_packing.nim semicongine/core.nim semicongine/core/vector.nim semicongine/rendering.nim semicongine/rendering/renderer.nim semicongine/rendering/shaders.nim semicongine/text/font.nim
diffstat 7 files changed, 193 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/semicongine/contrib/algorithms/texture_packing.nim	Wed Dec 04 22:17:41 2024 +0700
+++ b/semicongine/contrib/algorithms/texture_packing.nim	Fri Dec 06 22:20:39 2024 +0700
@@ -84,10 +84,10 @@
     for y in 0 ..< rect.h:
       for x in 0 ..< rect.w:
         when T is Gray:
-          assert result.atlas[rect.x + x, rect.y + y] == [0'u8],
+          assert result.atlas[rect.x + x, rect.y + y] == default(T),
             "Atlas texture packing encountered an overlap error"
         elif T is BGRA:
-          assert result.atlas[rect.x + x, rect.y + y] == [0'u8, 0'u8, 0'u8, 0'u8],
+          assert result.atlas[rect.x + x, rect.y + y] == default(T),
             "Atlas texture packing encountered an overlap error"
         else:
           {.error: "Unsupported type for texture packing".}
--- a/semicongine/core.nim	Wed Dec 04 22:17:41 2024 +0700
+++ b/semicongine/core.nim	Fri Dec 06 22:20:39 2024 +0700
@@ -1,3 +1,4 @@
+import std/hashes
 import std/macros
 import std/math
 import std/monotimes
--- a/semicongine/core/vector.nim	Wed Dec 04 22:17:41 2024 +0700
+++ b/semicongine/core/vector.nim	Fri Dec 06 22:20:39 2024 +0700
@@ -1,8 +1,8 @@
 type
-  TVec1*[T: SomeNumber] = array[1, T]
-  TVec2*[T: SomeNumber] = array[2, T]
-  TVec3*[T: SomeNumber] = array[3, T]
-  TVec4*[T: SomeNumber] = array[4, T]
+  TVec1*[T: SomeNumber] = distinct array[1, T]
+  TVec2*[T: SomeNumber] = distinct array[2, T]
+  TVec3*[T: SomeNumber] = distinct array[3, T]
+  TVec4*[T: SomeNumber] = distinct array[4, T]
   TVec* = TVec1 | TVec2 | TVec3 | TVec4
   Vec1f* = TVec1[float32]
   Vec2f* = TVec2[float32]
@@ -18,8 +18,107 @@
   Vec4u* = TVec4[uint32]
 
   # support for shorts
+  Vec1i8* = TVec1[int8]
+  Vec1u8* = TVec1[uint8]
   Vec2i8* = TVec2[int8]
+  Vec2u8* = TVec2[uint8]
   Vec3i8* = TVec3[int8]
+  Vec3u8* = TVec3[uint8]
+
+# stuff to allow working like an array, despite 'distinct'
+
+converter toArray*[T](v: TVec1[T]): array[1, T] =
+  array[1, T](v)
+
+converter toArray*[T](v: TVec2[T]): array[2, T] =
+  array[2, T](v)
+
+converter toArray*[T](v: TVec3[T]): array[3, T] =
+  array[3, T](v)
+
+converter toArray*[T](v: TVec4[T]): array[4, T] =
+  array[4, T](v)
+
+template `[]`*[T](v: TVec1[T], i: Ordinal): T =
+  (array[1, T](v))[i]
+
+template `[]`*[T](v: TVec2[T], i: Ordinal): T =
+  (array[2, T](v))[i]
+
+template `[]`*[T](v: TVec3[T], i: Ordinal): T =
+  (array[3, T](v))[i]
+
+template `[]`*[T](v: TVec4[T], i: Ordinal): T =
+  (array[4, T](v))[i]
+
+template `[]=`*[T](v: TVec1[T], i: Ordinal, a: T) =
+  (array[1, T](v))[i] = a
+
+template `[]=`*[T](v: TVec2[T], i: Ordinal, a: T) =
+  (array[2, T](v))[i] = a
+
+template `[]=`*[T](v: TVec3[T], i: Ordinal, a: T) =
+  (array[3, T](v))[i] = a
+
+template `[]=`*[T](v: TVec4[T], i: Ordinal, a: T) =
+  (array[4, T](v))[i] = a
+
+template `==`*[T](a, b: TVec1[T]): bool =
+  `==`(array[1, T](a), array[1, T](b))
+
+template `==`*[T](a, b: TVec2[T]): bool =
+  `==`(array[2, T](a), array[2, T](b))
+
+template `==`*[T](a, b: TVec3[T]): bool =
+  `==`(array[3, T](a), array[3, T](b))
+
+template `==`*[T](a, b: TVec4[T]): bool =
+  `==`(array[4, T](a), array[4, T](b))
+
+func len*(v: TVec1): int =
+  1
+func len*(v: TVec2): int =
+  2
+func len*(v: TVec3): int =
+  3
+func len*(v: TVec4): int =
+  4
+
+func sum*[T](v: TVec1[T]): T =
+  sum(array[1, T](v))
+func sum*[T](v: TVec2[T]): T =
+  sum(array[2, T](v))
+func sum*[T](v: TVec3[T]): T =
+  sum(array[3, T](v))
+func sum*[T](v: TVec4[T]): T =
+  sum(array[4, T](v))
+
+func hash*[T](v: TVec1[T]): Hash =
+  hash(array[1, T](v))
+func hash*[T](v: TVec2[T]): Hash =
+  hash(array[2, T](v))
+func hash*[T](v: TVec3[T]): Hash =
+  hash(array[3, T](v))
+func hash*[T](v: TVec4[T]): Hash =
+  hash(array[4, T](v))
+
+iterator items*[T](v: TVec1[T]): T =
+  yield v[0]
+
+iterator items*[T](v: TVec2[T]): T =
+  yield v[0]
+  yield v[1]
+
+iterator items*[T](v: TVec3[T]): T =
+  yield v[0]
+  yield v[1]
+  yield v[2]
+
+iterator items*[T](v: TVec4[T]): T =
+  yield v[0]
+  yield v[1]
+  yield v[2]
+  yield v[3]
 
 func toVec1*[T: SomeNumber](orig: TVec3[T] | TVec4[T]): TVec1[T] =
   TVec1[T]([orig[0]])
@@ -94,12 +193,23 @@
   vec4i(0, 0, 0, 0)
 
 # shortcuts Vec3i8
+func vec1i8*[T: SomeInteger](x: T): Vec1i8 =
+  Vec1i8([int8(x)])
+func vec1i8*(): Vec1i8 =
+  vec1i8(0)
+func vec1u8*[T: SomeInteger](x: T): Vec1u8 =
+  Vec1u8([uint8(x)])
+func vec1u8*(): Vec1u8 =
+  vec1u8(0)
+
+# missing: unsigned ones
 func vec2i8*[T, S: SomeInteger](x: T, y: S): Vec2i8 =
   Vec2i8([int8(x), int8(y)])
 func vec2i8*[T: SomeInteger](x: T): Vec2i8 =
   vec2i8(x, 0)
 func vec2i8*(): Vec2i8 =
   vec2i8(0, 0)
+
 func vec3i8*[T, S, U: SomeInteger](x: T, y: S, z: U): Vec3i8 =
   Vec3i8([int8(x), int8(y), int8(z)])
 func vec3i8*[T, S: SomeInteger](x: T, y: S): Vec3i8 =
--- a/semicongine/rendering.nim	Wed Dec 04 22:17:41 2024 +0700
+++ b/semicongine/rendering.nim	Fri Dec 06 22:20:39 2024 +0700
@@ -131,6 +131,8 @@
     IndexBufferMapped
     UniformBuffer
     UniformBufferMapped
+    StorageBuffer
+    StorageBufferMapped
 
   MemoryBlock* = object
     vk: VkDeviceMemory
@@ -198,12 +200,20 @@
         const `countname` {.inject.} = 1'u32
         body
         `bindingNumber`.inc
-    elif typeof(`valuename`) is GPUValue:
+    elif typeof(`valuename`) is GPUValue and
+        typeof(`valuename`).TBuffer in [UniformBuffer, UniformBufferMapped]:
       block:
         const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
         const `countname` {.inject.} = 1'u32
         body
         `bindingNumber`.inc
+    elif typeof(`valuename`) is GPUValue and
+        typeof(`valuename`).TBuffer in [StorageBuffer, StorageBufferMapped]:
+      block:
+        const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
+        const `countname` {.inject.} = 1'u32
+        body
+        `bindingNumber`.inc
     elif typeof(`valuename`) is array:
       when elementType(`valuename`) is ImageObject:
         block:
@@ -211,12 +221,20 @@
           const `countname` {.inject.} = uint32(typeof(`valuename`).len)
           body
           `bindingNumber`.inc
-      elif elementType(`valuename`) is GPUValue:
+      elif elementType(`valuename`) is GPUValue and
+          elementType(`valuename`).TBuffer in [UniformBuffer, UniformBufferMapped]:
         block:
           const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
           const `countname` {.inject.} = len(`valuename`).uint32
           body
           `bindingNumber`.inc
+      elif elementType(`valuename`) is GPUValue and
+          elementType(`valuename`).TBuffer in [StorageBuffer, StorageBufferMapped]:
+        block:
+          const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
+          const `countname` {.inject.} = len(`valuename`).uint32
+          body
+          `bindingNumber`.inc
       else:
         {.
           error: "Unsupported descriptor type: " & typetraits.name(typeof(`valuename`))
@@ -385,7 +403,8 @@
     initSwapchain(renderPass, vSync = vSync, tripleBuffering = tripleBuffering)
 
 proc destroyVulkan*() =
-  clearSwapchain()
+  if vulkan.swapchain != nil:
+    clearSwapchain()
   vkDestroyDevice(vulkan.device, nil)
   vkDestroySurfaceKHR(vulkan.instance, vulkan.surface, nil)
   if vulkan.debugMessenger.Valid:
--- a/semicongine/rendering/renderer.nim	Wed Dec 04 22:17:41 2024 +0700
+++ b/semicongine/rendering/renderer.nim	Fri Dec 06 22:20:39 2024 +0700
@@ -1,20 +1,16 @@
 func pointerAddOffset[T: SomeInteger](p: pointer, offset: T): pointer =
   cast[pointer](cast[T](p) + offset)
 
-func usage(bType: BufferType): seq[VkBufferUsageFlagBits] =
-  case bType
-  of VertexBuffer:
-    @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
-  of VertexBufferMapped:
-    @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT]
-  of IndexBuffer:
-    @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
-  of IndexBufferMapped:
-    @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT]
-  of UniformBuffer:
-    @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT]
-  of UniformBufferMapped:
-    @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT]
+const BUFFER_USAGE: array[BufferType, seq[VkBufferUsageFlagBits]] = [
+  VertexBuffer: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT],
+  VertexBufferMapped: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT],
+  IndexBuffer: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT],
+  IndexBufferMapped: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT],
+  UniformBuffer: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT],
+  UniformBufferMapped: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT],
+  StorageBuffer: @[VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT],
+  StorageBufferMapped: @[VK_BUFFER_USAGE_STORAGE_BUFFER_BIT],
+]
 
 proc getVkFormat(grayscale: bool, usage: openArray[VkImageUsageFlagBits]): VkFormat =
   let formats =
@@ -56,7 +52,8 @@
   typeof(gpuData).TBuffer
 
 func needsMapping(bType: BufferType): bool =
-  bType in [VertexBufferMapped, IndexBufferMapped, UniformBufferMapped]
+  bType in
+    [VertexBufferMapped, IndexBufferMapped, UniformBufferMapped, StorageBufferMapped]
 template needsMapping(gpuData: GPUData): untyped =
   gpuData.bufferType.needsMapping
 
@@ -259,7 +256,7 @@
     renderData: var RenderData, size: uint64, bufferType: BufferType
 ): Buffer =
   result = Buffer(
-    vk: svkCreateBuffer(size, bufferType.usage),
+    vk: svkCreateBuffer(size, BUFFER_USAGE[bufferType]),
     size: size,
     rawPointer: nil,
     offsetNextFree: 0,
@@ -394,6 +391,9 @@
     VkDescriptorPoolSize(
       thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit
     ),
+    VkDescriptorPoolSize(
+      thetype: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: descriptorPoolLimit
+    ),
   ]
   var poolInfo = VkDescriptorPoolCreateInfo(
     sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
@@ -504,13 +504,14 @@
 
 proc createVulkanImage(renderData: var RenderData, image: var ImageObject) =
   assert image.vk == VkImage(0), "Image has already been created"
-  var usage = @[VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_USAGE_SAMPLED_BIT]
+  var imgUsage = @[VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_USAGE_SAMPLED_BIT]
   if image.isRenderTarget:
-    usage.add VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
-  let format = getVkFormat(grayscale = elementType(image.data) is Gray, usage = usage)
+    imgUsage.add VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+  let format =
+    getVkFormat(grayscale = elementType(image.data) is Gray, usage = imgUsage)
 
   image.vk = svkCreate2DImage(
-    image.width, image.height, format, usage, image.samples, image.nLayers
+    image.width, image.height, format, imgUsage, image.samples, image.nLayers
   )
   renderData.images.add image.vk
   image.sampler = createSampler(
--- a/semicongine/rendering/shaders.nim	Wed Dec 04 22:17:41 2024 +0700
+++ b/semicongine/rendering/shaders.nim	Fri Dec 06 22:20:39 2024 +0700
@@ -79,6 +79,9 @@
     const n = typetraits.name(T)
     {.error: "Unsupported data type on GPU: " & n.}
 
+func glslType[T: SupportedGPUType](value: openArray[T]): string =
+  return glslType(default(T)) & "[]"
+
 func vkType[T: SupportedGPUType](value: T): VkFormat =
   when T is float32:
     VK_FORMAT_R32_SFLOAT
@@ -264,12 +267,23 @@
             ") uniform " & glslType(descriptorValue) & " " & descriptorName & ";"
           descriptorBinding.inc
         elif typeof(descriptorValue) is GPUValue:
+          let bufferType =
+            if typeof(descriptorValue).TBuffer in [UniformBuffer, UniformBufferMapped]:
+              "uniform"
+            else:
+              "readonly buffer"
           uniforms.add "layout(set=" & $setIndex & ", binding = " & $descriptorBinding &
-            ") uniform T" & descriptorName & " {"
+            ") " & bufferType & " T" & descriptorName & " {"
           when typeof(descriptorValue.data) is object:
             for blockFieldName, blockFieldValue in descriptorValue.data.fieldPairs():
-              assert typeof(blockFieldValue) is SupportedGPUType,
-                "uniform block field '" & blockFieldName & "' is not a SupportedGPUType"
+              when typeof(blockFieldValue) is array:
+                assert elementType(blockFieldValue) is SupportedGPUType,
+                  bufferType & " block field '" & blockFieldName &
+                    "' is not a SupportedGPUType"
+              else:
+                assert typeof(blockFieldValue) is SupportedGPUType,
+                  bufferType & " block field '" & blockFieldName &
+                    "' is not a SupportedGPUType"
               uniforms.add "  " & glslType(blockFieldValue) & " " & blockFieldName & ";"
             uniforms.add "} " & descriptorName & ";"
           else:
@@ -287,13 +301,24 @@
               descriptorName & "" & arrayDecl & ";"
             descriptorBinding.inc
           elif elementType(descriptorValue) is GPUValue:
+            let bufferType =
+              if typeof(descriptorValue).TBuffer in [UniformBuffer, UniformBufferMapped]:
+                "uniform"
+              else:
+                "readonly buffer"
             uniforms.add "layout(set=" & $setIndex & ", binding = " & $descriptorBinding &
-              ") uniform T" & descriptorName & " {"
+              ") " & bufferType & " T" & descriptorName & " {"
 
             for blockFieldName, blockFieldValue in default(elementType(descriptorValue)).data
             .fieldPairs():
-              assert typeof(blockFieldValue) is SupportedGPUType,
-                "uniform block field '" & blockFieldName & "' is not a SupportedGPUType"
+              when typeof(blockFieldValue) is array:
+                assert elementType(blockFieldValue) is SupportedGPUType,
+                  bufferType & " block field '" & blockFieldName &
+                    "' is not a SupportedGPUType"
+              else:
+                assert typeof(blockFieldValue) is SupportedGPUType,
+                  bufferType & " block field '" & blockFieldName &
+                    "' is not a SupportedGPUType"
               uniforms.add "  " & glslType(blockFieldValue) & " " & blockFieldName & ";"
             uniforms.add "} " & descriptorName & "[" & $descriptorValue.len & "];"
             descriptorBinding.inc
--- a/semicongine/text/font.nim	Wed Dec 04 22:17:41 2024 +0700
+++ b/semicongine/text/font.nim	Fri Dec 06 22:20:39 2024 +0700
@@ -97,10 +97,10 @@
     if width > 0 and height > 0:
       var bitmap = newSeq[Gray](width * height)
       for i in 0 ..< width * height:
-        bitmap[i] = [data[i].uint8]
+        bitmap[i] = vec1u8(data[i].uint8)
       images.add Image[Gray](width: width.uint32, height: height.uint32, data: bitmap)
     else:
-      images.add Image[Gray](width: 1, height: 1, data: @[[0'u8]])
+      images.add Image[Gray](width: 1, height: 1, data: @[vec1u8()])
 
     nativeFree(data)