changeset 109:8d24727c9795

did: refactor rendering/scene concept
author Sam <sam@basx.dev>
date Wed, 29 Mar 2023 23:35:39 +0700
parents 70f92081d2c1
children 3bbc94a83404
files src/semicongine/entity.nim src/semicongine/mesh.nim src/semicongine/scene.nim src/semicongine/vulkan/instance.nim src/semicongine/vulkan/pipeline.nim src/semicongine/vulkan/renderpass.nim src/semicongine/vulkan/swapchain.nim tests/test_vulkan_wrapper.nim
diffstat 8 files changed, 97 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/entity.nim	Tue Mar 28 00:20:49 2023 +0700
+++ b/src/semicongine/entity.nim	Wed Mar 29 23:35:39 2023 +0700
@@ -5,46 +5,46 @@
 
 type
   Component* = ref object of RootObj
-    thing*: Entity
+    entity*: Entity
 
   Entity* = ref object of RootObj
     name*: string
     transform*: Mat44 # todo: cache transform + only update VBO when transform changed
     parent*: Entity
     children*: seq[Entity]
-    parts*: seq[Component]
+    components*: seq[Component]
 
 
-func `$`*(thing: Entity): string = thing.name
+func `$`*(entity: Entity): string = entity.name
 method `$`*(part: Component): string {.base.} =
-  if part.thing != nil:
-    &"{part.thing} -> Component"
+  if part.entity != nil:
+    &"{part.entity} -> Component"
   else:
     &"Standalone Component"
 
-proc add*(thing: Entity, child: Entity) =
-  child.parent = thing
-  thing.children.add child
-proc add*(thing: Entity, part: Component) =
-  part.thing = thing
-  thing.parts.add part
-proc add*(thing: Entity, children: seq[Entity]) =
+proc add*(entity: Entity, child: Entity) =
+  child.parent = entity
+  entity.children.add child
+proc add*(entity: Entity, part: Component) =
+  part.entity = entity
+  entity.components.add part
+proc add*(entity: Entity, children: seq[Entity]) =
   for child in children:
-    child.parent = thing
-    thing.children.add child
-proc add*(thing: Entity, parts: seq[Component]) =
-  for part in parts:
-    part.thing = thing
-    thing.parts.add part
+    child.parent = entity
+    entity.children.add child
+proc add*(entity: Entity, components: seq[Component]) =
+  for part in components:
+    part.entity = entity
+    entity.components.add part
 
-func newThing*(name: string = ""): Entity =
+func newEntity*(name: string = ""): Entity =
   result = new Entity
   result.name = name
   result.transform = Unit44
   if result.name == "":
     result.name = &"Entity[{$(cast[ByteAddress](result))}]"
 
-func newThing*(name: string, firstChild: Entity, children: varargs[
+func newEntity*(name: string, firstChild: Entity, children: varargs[
     Entity]): Entity =
   result = new Entity
   result.add firstChild
@@ -55,32 +55,32 @@
   if result.name == "":
     result.name = &"Entity[{$(cast[ByteAddress](result))}]"
 
-proc newThing*(name: string, firstPart: Component, parts: varargs[Component]): Entity =
+proc newEntity*(name: string, firstPart: Component, components: varargs[Component]): Entity =
   result = new Entity
   result.name = name
   result.add firstPart
-  for part in parts:
+  for part in components:
     result.add part
   if result.name == "":
     result.name = &"Entity[{$(cast[ByteAddress](result))}]"
   result.transform = Unit44
 
-func getModelTransform*(thing: Entity): Mat44 =
+func getModelTransform*(entity: Entity): Mat44 =
   result = Unit44
-  var currentThing = thing
-  while currentThing != nil:
-    result = currentThing.transform * result
-    currentThing = currentThing.parent
+  var currentEntity = entity
+  while currentEntity != nil:
+    result = currentEntity.transform * result
+    currentEntity = currentEntity.parent
 
 iterator allPartsOfType*[T: Component](root: Entity): T =
   var queue = @[root]
   while queue.len > 0:
-    let thing = queue.pop
-    for part in thing.parts:
+    let entity = queue.pop
+    for part in entity.components:
       if part of T:
         yield T(part)
-    for i in countdown(thing.children.len - 1, 0):
-      queue.add thing.children[i]
+    for i in countdown(entity.children.len - 1, 0):
+      queue.add entity.children[i]
 
 func firstWithName*(root: Entity, name: string): Entity =
   var queue = @[root]
@@ -97,7 +97,7 @@
     let next = queue.pop
     for child in next.children:
       if child.name == name:
-        for part in child.parts:
+        for part in child.components:
           if part of T:
             return T(part)
       queue.add child
@@ -117,12 +117,12 @@
     let next = queue.pop
     for child in next.children:
       if child.name == name:
-        for part in child.parts:
+        for part in child.components:
           if part of T:
             result.add T(part)
       queue.add child
 
-iterator allThings*(root: Entity): Entity =
+iterator allEntities*(root: Entity): Entity =
   var queue = @[root]
   while queue.len > 0:
     let next = queue.pop
--- a/src/semicongine/mesh.nim	Tue Mar 28 00:20:49 2023 +0700
+++ b/src/semicongine/mesh.nim	Wed Mar 29 23:35:39 2023 +0700
@@ -8,7 +8,6 @@
 import ./math/vector
 
 type
-  # TODO: make single mesh type, with case-of attribute for indices
   Mesh*[T: object, U: uint16|uint32] = ref object of Part
     vertexData*: T
     case indexed*: bool
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/semicongine/scene.nim	Wed Mar 29 23:35:39 2023 +0700
@@ -0,0 +1,13 @@
+import std/options
+
+import ./vulkan/api
+import ./entity
+import ./vulkan/buffer
+
+type
+  Scene* = object
+    root*: Entity
+
+# attribute_buffers, number_of_vertices, number_of_instances, (indexbuffer, indextype)
+proc getBufferSets*(scene: Scene): seq[(seq[Buffer], uint32, uint32, Option[(Buffer, VkIndexType)])] =
+  result
--- a/src/semicongine/vulkan/instance.nim	Tue Mar 28 00:20:49 2023 +0700
+++ b/src/semicongine/vulkan/instance.nim	Wed Mar 29 23:35:39 2023 +0700
@@ -1,5 +1,7 @@
 import std/strformat
+import std/tables
 import std/sequtils
+import std/logging
 
 import ./api
 import ./utils
@@ -89,13 +91,21 @@
   instance.vk.vkDestroyInstance(nil)
   instance.vk.reset()
 
+const LEVEL_MAPPING = {
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: lvlDebug,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: lvlInfo,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: lvlWarn,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: lvlError,
+}.toTable
+
 proc defaultDebugCallback(
   messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT,
   messageTypes: VkDebugUtilsMessageTypeFlagsEXT,
   pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT,
   userData: pointer
 ): VkBool32 {.cdecl.} =
-  echo &"{messageSeverity}: {toEnums messageTypes}: {pCallbackData.pMessage}"
+
+  log LEVEL_MAPPING[messageSeverity], &"{toEnums messageTypes}: {pCallbackData.pMessage}"
   return false
 
 proc createDebugMessenger*(
--- a/src/semicongine/vulkan/pipeline.nim	Tue Mar 28 00:20:49 2023 +0700
+++ b/src/semicongine/vulkan/pipeline.nim	Wed Mar 29 23:35:39 2023 +0700
@@ -1,9 +1,12 @@
+import std/options
+
 import ./api
 import ./utils
 import ./device
-import ./shader
 import ./descriptor
 
+import ../scene
+
 type
   Pipeline* = object
     device*: Device
@@ -13,9 +16,24 @@
     descriptorPool*: DescriptorPool
     descriptorSets*: seq[DescriptorSet]
 
-proc run*(pipeline: Pipeline, commandBuffer: VkCommandBuffer) =
-  # pipeline an descriptors bound
-  echo "Running pipeline"
+proc run*(pipeline: Pipeline, commandBuffer: VkCommandBuffer, inFlightFrame: int, scene: Scene) =
+  var varPipeline = pipeline
+  commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.vk)
+  commandBuffer.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 1, addr(varPipeline.descriptorSets[inFlightFrame].vk), 0, nil)
+  for (bufferSet, count, instanceCount, indexBuffer) in scene.getBufferSets():
+    var buffers: seq[VkBuffer]
+    var offsets: seq[VkDeviceSize]
+    for buffer in bufferSet:
+      buffers.add buffer.vk
+      offsets.add VkDeviceSize(0)
+
+    commandBuffer.vkCmdBindVertexBuffers(firstBinding=0'u32, bindingCount=uint32(buffers.len), pBuffers=buffers.toCPointer(), pOffsets=offsets.toCPointer())
+    if indexBuffer.isSome:
+      commandBuffer.vkCmdBindIndexBuffer(indexBuffer.get()[0].vk, VkDeviceSize(0), indexBuffer.get()[1])
+      commandBuffer.vkCmdDrawIndexed(indexCount=count, instanceCount=instanceCount, firstIndex=0, vertexOffset=0, firstInstance=0)
+
+    else:
+      commandBuffer.vkCmdDraw(vertexCount=count, instanceCount=instanceCount, firstVertex=0, firstInstance=0)
 
 proc destroy*(pipeline: var Pipeline) =
   assert pipeline.device.vk.valid
--- a/src/semicongine/vulkan/renderpass.nim	Tue Mar 28 00:20:49 2023 +0700
+++ b/src/semicongine/vulkan/renderpass.nim	Wed Mar 29 23:35:39 2023 +0700
@@ -218,7 +218,15 @@
         clearColor: clearColor
       )
     ]
-    dependencies: seq[VkSubpassDependency]
+    # dependencies seems to be optional, TODO: benchmark difference
+    dependencies = @[VkSubpassDependency(
+      srcSubpass: VK_SUBPASS_EXTERNAL,
+      dstSubpass: 0,
+      srcStageMask: toBits [VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT],
+      srcAccessMask: VkAccessFlags(0),
+      dstStageMask: toBits [VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT],
+      dstAccessMask: toBits [VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT],
+    )]
   result = device.createRenderPass(attachments=attachments, subpasses=subpasses, dependencies=dependencies, inFlightFrames=inFlightFrames)
   result.attachPipeline(vertexShader, fragmentShader, 0)
 
--- a/src/semicongine/vulkan/swapchain.nim	Tue Mar 28 00:20:49 2023 +0700
+++ b/src/semicongine/vulkan/swapchain.nim	Wed Mar 29 23:35:39 2023 +0700
@@ -11,6 +11,7 @@
 import ./pipeline
 import ./syncing
 
+import ../scene
 import ../math
 
 type
@@ -99,7 +100,7 @@
 
   return (swapchain, createResult)
 
-proc drawNextFrame*(swapchain: var Swapchain): bool =
+proc drawNextFrame*(swapchain: var Swapchain, scene: Scene): bool =
   assert swapchain.device.vk.valid
   assert swapchain.vk.valid
   assert swapchain.device.firstGraphicsQueue().isSome
@@ -131,11 +132,7 @@
   ):
     for i in 0 ..< swapchain.renderpass.subpasses.len:
       var pipeline = swapchain.renderpass.pipelines[i]
-      commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.vk)
-      commandBuffer.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 1, addr(pipeline.descriptorSets[swapchain.currentInFlight].vk), 0, nil)
-      pipeline.run(commandBuffer)
-
-      swapchain.renderpass.pipelines[i].run(commandBuffer)
+      pipeline.run(commandBuffer, swapchain.currentInFlight, scene)
       if i < swapchain.renderpass.subpasses.len - 1:
         commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE)
 
--- a/tests/test_vulkan_wrapper.nim	Tue Mar 28 00:20:49 2023 +0700
+++ b/tests/test_vulkan_wrapper.nim	Wed Mar 29 23:35:39 2023 +0700
@@ -3,6 +3,8 @@
 import semicongine/vulkan
 import semicongine/platform/window
 import semicongine/math
+import semicongine/entity
+import semicongine/scene
 
 type
   Vertex = object
@@ -75,9 +77,11 @@
   if res != VK_SUCCESS:
     raise newException(Exception, "Unable to create swapchain")
 
+  var thescene = Scene(root: newEntity("scene"))
+
   echo "All successfull"
   for i in 0 ..< 2:
-    discard swapchain.drawNextFrame()
+    discard swapchain.drawNextFrame(thescene)
   echo "Rendered ", swapchain.framesRendered, " frames"
   echo "Start cleanup"