changeset 327:a63bd8f29252

add: make same attribute for different shaders work correctly, yipie!
author Sam <sam@basx.dev>
date Fri, 25 Aug 2023 01:09:23 +0700
parents 4ec852355750
children 8d0ffcacc7e3
files src/semicongine/engine.nim src/semicongine/renderer.nim src/semicongine/vulkan/drawable.nim tests/test_vulkan_wrapper.nim
diffstat 4 files changed, 32 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/engine.nim	Fri Aug 25 00:29:51 2023 +0700
+++ b/src/semicongine/engine.nim	Fri Aug 25 01:09:23 2023 +0700
@@ -110,6 +110,7 @@
 proc addScene*(engine: var Engine, scene: var Scene) =
   assert engine.renderer.isSome
   engine.renderer.get.setupDrawableBuffers(scene)
+  engine.renderer.get.updateMeshData(scene, forceAll=true)
 
 proc renderScene*(engine: var Engine, scene: var Scene) =
   assert engine.state == Running
--- a/src/semicongine/renderer.nim	Fri Aug 25 00:29:51 2023 +0700
+++ b/src/semicongine/renderer.nim	Fri Aug 25 01:09:23 2023 +0700
@@ -31,7 +31,7 @@
     uniformBuffers*: Table[VkPipeline, seq[Buffer]] # one per frame-in-flight
     textures*: Table[string, seq[VulkanTexture]] # per frame-in-flight
     attributeLocation*: Table[string, MemoryPerformanceHint]
-    attributeBindingNumber*: Table[string, int]
+    vertexBufferOffsets*: Table[(int, string), int]
     descriptorPools*: Table[VkPipeline, DescriptorPool]
     descriptorSets*: Table[VkPipeline, seq[DescriptorSet]]
     materials: seq[Material]
@@ -135,19 +135,13 @@
       preferVRAM=true,
     )
 
-  # create vertex buffers and calculcate offsets
+  # calculcate offsets for attributes in vertex buffers
   # trying to use one buffer per memory type
-  var
-    perLocationOffsets: Table[MemoryPerformanceHint, int]
-    perLocationSizes: Table[MemoryPerformanceHint, int]
-    bindingNumber = 0
+  var perLocationSizes: Table[MemoryPerformanceHint, int]
   for hint in MemoryPerformanceHint:
-    perLocationOffsets[hint] = 0
     perLocationSizes[hint] = 0
   for attribute in inputs:
     scenedata.attributeLocation[attribute.name] = attribute.memoryPerformanceHint
-    scenedata.attributeBindingNumber[attribute.name] = bindingNumber
-    inc bindingNumber
     # setup one buffer per attribute-location-type
     for mesh in scene.meshes:
       # align size to VERTEX_ATTRIB_ALIGNMENT bytes (the important thing is the correct alignment of the offsets, but
@@ -155,6 +149,8 @@
       if perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0:
         perLocationSizes[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT)
       perLocationSizes[attribute.memoryPerformanceHint] += mesh.attributeSize(attribute.name)
+
+  # create vertex buffers
   for memoryPerformanceHint, bufferSize in perLocationSizes.pairs:
     if bufferSize > 0:
       scenedata.vertexBuffers[memoryPerformanceHint] = renderer.device.createBuffer(
@@ -164,18 +160,26 @@
         preferVRAM=true,
       )
 
-  # fill vertex buffers
+  # calculate offset of each attribute of all meshes
+  var perLocationOffsets: Table[MemoryPerformanceHint, int]
   var indexBufferOffset = 0
+  for hint in MemoryPerformanceHint:
+    perLocationOffsets[hint] = 0
   for (meshIndex, mesh) in enumerate(scene.meshes):
-    var offsets: seq[(string, MemoryPerformanceHint, int)]
     for attribute in inputs:
-      offsets.add (attribute.name, attribute.memoryPerformanceHint, perLocationOffsets[attribute.memoryPerformanceHint])
-      var (pdata, size) = mesh.getRawData(attribute.name)
-      if pdata != nil: # no data
-        scenedata.vertexBuffers[attribute.memoryPerformanceHint].setData(pdata, size, perLocationOffsets[attribute.memoryPerformanceHint])
-        perLocationOffsets[attribute.memoryPerformanceHint] += size
-        if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0:
-          perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT)
+      scenedata.vertexBufferOffsets[(meshIndex, attribute.name)] = perLocationOffsets[attribute.memoryPerformanceHint]
+      let size = mesh.getRawData(attribute.name)[1]
+      perLocationOffsets[attribute.memoryPerformanceHint] += size
+      if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0:
+        perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT)
+
+    # fill offsets (as sequence corresponds to shader input binding)
+    var offsets: Table[VkPipeline, seq[(string, MemoryPerformanceHint, int)]]
+    for subpass_i in 0 ..< renderer.renderPass.subpasses.len:
+      for materialType, pipeline in renderer.renderPass.subpasses[subpass_i].pipelines.pairs:
+        offsets[pipeline.vk] = newSeq[(string, MemoryPerformanceHint, int)]()
+        for attribute in pipeline.inputs:
+          offsets[pipeline.vk].add (attribute.name, attribute.memoryPerformanceHint, scenedata.vertexBufferOffsets[(meshIndex, attribute.name)])
 
     let indexed = mesh.indexType != MeshIndexType.None
     var drawable = Drawable(
@@ -245,16 +249,16 @@
     return
   var (pdata, size) = scene.meshes[meshIndex].getRawData(attribute)
   let memoryPerformanceHint = renderer.scenedata[scene].attributeLocation[attribute]
-  let bindingNumber = renderer.scenedata[scene].attributeBindingNumber[attribute]
-  renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].setData(pdata, size, drawable.bufferOffsets[bindingNumber][2])
+  renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].setData(pdata, size, renderer.scenedata[scene].vertexBufferOffsets[(meshIndex, attribute)])
 
-proc updateMeshData*(renderer: var Renderer, scene: var Scene) =
+proc updateMeshData*(renderer: var Renderer, scene: var Scene, forceAll=false) =
   assert scene in renderer.scenedata
 
   for (drawable, meshIndex) in renderer.scenedata[scene].drawables.mitems:
     if scene.meshes[meshIndex].attributes.contains(TRANSFORMATTRIBUTE):
       scene.meshes[meshIndex].updateInstanceTransforms(TRANSFORMATTRIBUTE)
-    for attribute in scene.meshes[meshIndex].dirtyAttributes:
+    let attrs = (if forceAll: scene.meshes[meshIndex].attributes else: scene.meshes[meshIndex].dirtyAttributes)
+    for attribute in attrs:
       renderer.refreshMeshAttributeData(scene, drawable, meshIndex, attribute)
       debug &"Update mesh attribute {attribute}"
     scene.meshes[meshIndex].clearDirtyAttributes()
@@ -310,7 +314,7 @@
 
         for (drawable, meshIndex) in renderer.scenedata[scene].drawables:
           if scene.meshes[meshIndex].material != nil and scene.meshes[meshIndex].material.materialType == materialType:
-            drawable.draw(commandBuffer, vertexBuffers=renderer.scenedata[scene].vertexBuffers, indexBuffer=renderer.scenedata[scene].indexBuffer)
+            drawable.draw(commandBuffer, vertexBuffers=renderer.scenedata[scene].vertexBuffers, indexBuffer=renderer.scenedata[scene].indexBuffer, pipeline.vk)
 
     if i < renderer.renderPass.subpasses.len - 1:
       commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE)
--- a/src/semicongine/vulkan/drawable.nim	Fri Aug 25 00:29:51 2023 +0700
+++ b/src/semicongine/vulkan/drawable.nim	Fri Aug 25 01:09:23 2023 +0700
@@ -8,7 +8,7 @@
 type
   Drawable* = object
     elementCount*: int # number of vertices or indices
-    bufferOffsets*: seq[(string, MemoryPerformanceHint, int)] # list of buffers and list of offset for each attribute in that buffer
+    bufferOffsets*: Table[VkPipeline, seq[(string, MemoryPerformanceHint, int)]] # list of buffers and list of offset for each attribute in that buffer
     instanceCount*: int # number of instance
     case indexed*: bool
     of true:
@@ -23,13 +23,13 @@
   else:
     &"Drawable(elementCount: {drawable.elementCount}, instanceCount: {drawable.instanceCount}, bufferOffsets: {drawable.bufferOffsets})"
 
-proc draw*(drawable: Drawable, commandBuffer: VkCommandBuffer, vertexBuffers: Table[MemoryPerformanceHint, Buffer], indexBuffer: Buffer) =
+proc draw*(drawable: Drawable, commandBuffer: VkCommandBuffer, vertexBuffers: Table[MemoryPerformanceHint, Buffer], indexBuffer: Buffer, pipeline: VkPipeline) =
     debug "Draw ", drawable
 
     var buffers: seq[VkBuffer]
     var offsets: seq[VkDeviceSize]
 
-    for (name, performanceHint, offset) in drawable.bufferOffsets:
+    for (name, performanceHint, offset) in drawable.bufferOffsets[pipeline]:
       buffers.add vertexBuffers[performanceHint].vk
       offsets.add VkDeviceSize(offset)
 
--- a/tests/test_vulkan_wrapper.nim	Fri Aug 25 00:29:51 2023 +0700
+++ b/tests/test_vulkan_wrapper.nim	Fri Aug 25 01:09:23 2023 +0700
@@ -189,7 +189,7 @@
       outputs=[attr[Vec4f]("color")],
       uniforms=[attr[Vec4f]("color")],
       vertexCode="""gl_Position = vec4(position, 1.0) * transform; outcolor = Uniforms.color;""",
-      fragmentCode="color = vec4(0, 0, 1, 1);",
+      fragmentCode="color = outcolor;",
     )
   engine.initRenderer({
     "my_material": shaderConfiguration1,