diff semicongine/renderer.nim @ 870:b975eab2b694

did: improve dynamic array, mesh and material APIs a ton, changes in material attributes are now detected and will trigger uniform-updates
author Sam <sam@basx.dev>
date Sun, 07 Jan 2024 00:56:44 +0700
parents 65afec4cb6c6
children 164b41a2d5a6
line wrap: on
line diff
--- a/semicongine/renderer.nim	Thu Jan 04 21:13:11 2024 +0700
+++ b/semicongine/renderer.nim	Sun Jan 07 00:56:44 2024 +0700
@@ -213,8 +213,7 @@
     for attribute in inputs:
       scenedata.vertexBufferOffsets[(mesh, attribute.name)] = perLocationOffsets[attribute.memoryPerformanceHint]
       if mesh[].attributes.contains(attribute.name):
-        let size = mesh[].getRawData(attribute.name)[1]
-        perLocationOffsets[attribute.memoryPerformanceHint] += size
+        perLocationOffsets[attribute.memoryPerformanceHint] += mesh[].attributeSize(attribute.name)
         if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0:
           perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT)
 
@@ -322,9 +321,12 @@
   if not (attribute in renderer.scenedata[scene].attributeLocation):
     return
 
-  let (pdata, size) = mesh[].getRawData(attribute)
   let memoryPerformanceHint = renderer.scenedata[scene].attributeLocation[attribute]
-  renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].setData(pdata, size, renderer.scenedata[scene].vertexBufferOffsets[(mesh, attribute)])
+  renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].setData(
+    mesh[].getPointer(attribute),
+    mesh[].attributeSize(attribute),
+    renderer.scenedata[scene].vertexBufferOffsets[(mesh, attribute)]
+  )
 
 proc updateMeshData*(renderer: var Renderer, scene: var Scene, forceAll=false) =
   assert scene in renderer.scenedata
@@ -340,13 +342,10 @@
 
 proc updateUniformData*(renderer: var Renderer, scene: var Scene, forceAll=false) =
   assert scene in renderer.scenedata
-  # TODO: maybe check for dirty materials too, but atm we copy materials into the
-  # renderers scenedata, so they are immutable after initialization, would 
-  # need to allow updates of materials too in order to make sense
 
   let dirty = scene.dirtyShaderGlobals
-  if not forceAll and dirty.len == 0:
-    return
+  # if not forceAll and dirty.len == 0:
+    # return
 
   if forceAll:
     debug "Update uniforms because 'forceAll' was given"
@@ -361,6 +360,10 @@
         renderer.scenedata[scene].uniformBuffers.hasKey(shaderPipeline.vk) and
         renderer.scenedata[scene].uniformBuffers[shaderPipeline.vk].len != 0
       ):
+        var dirtyMaterialAttribs: seq[string]
+        for material in renderer.scenedata[scene].materials[materialType].mitems:
+          dirtyMaterialAttribs.add material.dirtyAttributes
+          material.clearDirtyAttributes()
         assert renderer.scenedata[scene].uniformBuffers[shaderPipeline.vk][renderer.swapchain.currentInFlight].vk.valid
         if forceAll:
           for buffer in renderer.scenedata[scene].uniformBuffers[shaderPipeline.vk]:
@@ -369,7 +372,7 @@
         var offset = 0
         # loop over all uniforms of the shader-shaderPipeline
         for uniform in shaderPipeline.uniforms:
-          if dirty.contains(uniform.name) or forceAll: # only update uniforms if necessary
+          if dirty.contains(uniform.name) or dirtyMaterialAttribs.contains(uniform.name) or forceAll: # only update uniforms if necessary
             var value = initDataList(uniform.theType)
             if scene.shaderGlobals.hasKey(uniform.name):
               assert scene.shaderGlobals[uniform.name].thetype == uniform.thetype
@@ -382,14 +385,13 @@
                   foundValue = true
               assert foundValue, &"Uniform '{uniform.name}' not found in scene shaderGlobals or materials"
             assert (uniform.arrayCount == 0 and value.len == 1) or value.len == uniform.arrayCount, &"Uniform '{uniform.name}' found has wrong length (shader declares {uniform.arrayCount} but shaderGlobals and materials provide {value.len})"
-            let (pdata, size) = value.getRawData()
-            assert size == uniform.size, "During uniform update: gathered value has size {size} but uniform expects size {uniform.size}"
+            assert value.size == uniform.size, "During uniform update: gathered value has size {value.size} but uniform expects size {uniform.size}"
             debug &"  update uniform {uniform.name} with value: {value}"
             # TODO: technically we would only need to update the uniform buffer of the current
             # frameInFlight (I think), but we don't track for which frame the shaderglobals are no longer dirty
             # therefore we have to update the uniform values in all buffers, of all inFlightframes (usually 2)
             for buffer in renderer.scenedata[scene].uniformBuffers[shaderPipeline.vk]:
-              buffer.setData(pdata, size, offset)
+              buffer.setData(value.getPointer(), value.size, offset)
           offset += uniform.size
   scene.clearDirtyShaderGlobals()