From ef0679d3dab4b0f2777cd4a60ec2f0ad0c3836c6 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 16 May 2024 10:23:33 +0200 Subject: [PATCH] [Sg] Use single value attributes for IndexedGeometry --- .../Resources/Buffers/SingleValueBuffer.fs | 23 ++- src/Aardvark.SceneGraph/SgFSharp.fs | 179 ++++++------------ 2 files changed, 78 insertions(+), 124 deletions(-) diff --git a/src/Aardvark.Rendering/Resources/Buffers/SingleValueBuffer.fs b/src/Aardvark.Rendering/Resources/Buffers/SingleValueBuffer.fs index eead7aa8..f04962a7 100644 --- a/src/Aardvark.Rendering/Resources/Buffers/SingleValueBuffer.fs +++ b/src/Aardvark.Rendering/Resources/Buffers/SingleValueBuffer.fs @@ -61,4 +61,25 @@ type SingleValueBuffer<'T when 'T : unmanaged>(value : aval<'T>) = member x.Accept(visitor) = value.Accept(visitor) member x.AllInputsProcessed(obj) = value.AllInputsProcessed(obj) member x.InputChanged(t, o) = value.InputChanged(t, o) - member x.Mark() = value.Mark() \ No newline at end of file + member x.Mark() = value.Mark() + +[] +module SingleValueBuffer = + + [] + module private GenericDispatch = + open System.Reflection + + [] + type Dispatcher() = + static member ToSingleValueBuffer<'T when 'T : unmanaged>(value: obj) : ISingleValueBuffer = + SingleValueBuffer<'T>(unbox<'T> value) + + module Method = + let private flags = BindingFlags.Static ||| BindingFlags.NonPublic ||| BindingFlags.Public + let toSingleValueBuffer = typeof.GetMethod("ToSingleValueBuffer", flags) + + /// Creates a single value buffer from an untyped value. + let create (value: obj) = + let mi = Method.toSingleValueBuffer.MakeGenericMethod [| value.GetType() |] + mi.Invoke(null, [| value |]) |> unbox \ No newline at end of file diff --git a/src/Aardvark.SceneGraph/SgFSharp.fs b/src/Aardvark.SceneGraph/SgFSharp.fs index 1228a810..f26ee1e8 100644 --- a/src/Aardvark.SceneGraph/SgFSharp.fs +++ b/src/Aardvark.SceneGraph/SgFSharp.fs @@ -39,30 +39,36 @@ module SgFSharp = module Caching = // Note: we need these caches because of the AVal.maps below - let bufferCache = ConditionalWeakTable() + let private cache = ConditionalWeakTable() - let bufferOfArray (m : aval<'a[]>) = - match bufferCache.TryGetValue m with - | (true, r) -> r + let private getOrCreate (create: 'T1 -> 'T2) (value: 'T1) : 'T2 = + match cache.TryGetValue value with + | (true, r) when r.GetType() = typeof<'T2> -> unbox<'T2> r | _ -> - let b = m |> AVal.map (fun a -> ArrayBuffer a :> IBuffer) - let r = BufferView(b, typeof<'a>) - bufferCache.Add(m, r) + let r = create value + cache.Add(value, r) r - let bufferOfTrafos (m : aval) = - match bufferCache.TryGetValue m with - | (true, r) -> r - | _ -> - let b = - m |> AVal.map (fun a -> - let a = a |> Array.map (Trafo.forward >> M44f) - ArrayBuffer a :> IBuffer - ) - - let r = BufferView(b, typeof) - bufferCache.Add(m, r) - r + let bufferOfArray (value: aval<'T[]>) : BufferView = + value |> getOrCreate (fun value -> + let b = value |> AVal.map (fun a -> ArrayBuffer a :> IBuffer) + BufferView(b, typeof<'T>) + ) + + let buffersOfTrafos (value: aval) : BufferView * BufferView = + value |> getOrCreate (fun value -> + let forward = value |> AVal.map (fun a -> + let a = a |> Array.map (Trafo.forward >> M44f) + ArrayBuffer a :> IBuffer + ) + + let backward = value |> AVal.map (fun a -> + let a = a |> Array.map (Trafo.backward >> M44f) + ArrayBuffer a :> IBuffer + ) + + BufferView(forward, typeof), BufferView(backward, typeof) + ) module Sg = open SgFSharpHelpers @@ -107,7 +113,7 @@ module SgFSharp = Sg.AdapterNode(o) :> ISg /// Combines the render objects in the given adaptive set. - let renderObjectSet (s : #aset) = + let renderObjectSet (s : #aset) = Sg.RenderObjectNode(s) :> ISg /// Applies the given activation function to the the given scene graph. @@ -790,80 +796,22 @@ module SgFSharp = let indirectDraw (mode : IndexedGeometryMode) (buffer : aval) = Sg.IndirectRenderNode(buffer, mode) :> ISg - /// Creates a draw call from the given indexed geometry. - let ofIndexedGeometry (g : IndexedGeometry) = - let attributes = - g.IndexedAttributes |> Seq.map (fun (KeyValue(k,v)) -> - let t = v.GetType().GetElementType() - let view = BufferView(~~(ArrayBuffer(v) :> IBuffer), t) - - k, view - ) |> Map.ofSeq - - - let index, faceVertexCount = - if g.IsIndexed then - g.IndexArray, g.IndexArray.Length - else - null, g.IndexedAttributes.[DefaultSemantic.Positions].Length - - let call = - DrawCallInfo( - FaceVertexCount = faceVertexCount, - FirstIndex = 0, - InstanceCount = 1, - FirstInstance = 0, - BaseVertex = 0 - ) - - let sg = Sg.VertexAttributeApplicator(attributes, Sg.RenderNode(call,g.Mode)) :> ISg - if not (isNull index) then - Sg.VertexIndexApplicator(BufferView.ofArray index, sg) :> ISg - else - sg - - /// Creates a draw call from the given indexed geometry and instance count. - let ofIndexedGeometryInstanced (g : IndexedGeometry) (instanceCount : int) = - let attributes = - g.IndexedAttributes |> Seq.map (fun (KeyValue(k,v)) -> - let t = v.GetType().GetElementType() - let view = BufferView(~~(ArrayBuffer(v) :> IBuffer), t) - - k, view - ) |> Map.ofSeq - - - let index, faceVertexCount = - if g.IsIndexed then - g.IndexArray, g.IndexArray.Length - else - null, g.IndexedAttributes.[DefaultSemantic.Positions].Length - - let call = - DrawCallInfo( - FaceVertexCount = faceVertexCount, - FirstIndex = 0, - InstanceCount = instanceCount, - FirstInstance = 0, - BaseVertex = 0 - ) - - let sg = Sg.VertexAttributeApplicator(attributes, Sg.RenderNode(call, g.Mode)) :> ISg - if not (isNull index) then - Sg.VertexIndexApplicator(BufferView.ofArray index, sg) :> ISg - else - sg - /// Creates a draw call from the given indexed geometry and an adpative instance count. let ofIndexedGeometryInstancedA (g : IndexedGeometry) (instanceCount : aval) = let attributes = - g.IndexedAttributes |> Seq.map (fun (KeyValue(k,v)) -> - let t = v.GetType().GetElementType() - let view = BufferView(~~(ArrayBuffer(v) :> IBuffer), t) + let indexed = + g.IndexedAttributes |> Seq.map (fun (KeyValue(sem, attr)) -> + sem, BufferView(attr) + ) |> Map.ofSeq - k, view - ) |> Map.ofSeq + let single = + if isNull g.SingleAttributes then Map.empty + else + g.SingleAttributes |> Seq.map (fun (KeyValue(sem, value)) -> + sem, BufferView(SingleValueBuffer.create value) + ) |> Map.ofSeq + Map.union indexed single let index, faceVertexCount = if g.IsIndexed then @@ -886,43 +834,28 @@ module SgFSharp = else sg - /// Creates a draw call, supplying the given transformations as per-instance attributes with - /// name DefaultSemantic.InstanceTrafo. - let instancedGeometry (trafos : aval) (g : IndexedGeometry) = - let vertexAttributes = - g.IndexedAttributes |> Seq.map (fun (KeyValue(k,v)) -> - let t = v.GetType().GetElementType() - let view = BufferView(~~(ArrayBuffer(v) :> IBuffer), t) - - k, view - ) |> Map.ofSeq - - let index, faceVertexCount = - if g.IsIndexed then - g.IndexArray, g.IndexArray.Length - else - null, g.IndexedAttributes.[DefaultSemantic.Positions].Length - - let call = trafos |> AVal.map (fun t -> - DrawCallInfo( - FaceVertexCount = faceVertexCount, - FirstIndex = 0, - InstanceCount = t.Length, - FirstInstance = 0, - BaseVertex = 0 - ) - ) + /// Creates a draw call from the given indexed geometry and instance count. + let ofIndexedGeometryInstanced (g : IndexedGeometry) (instanceCount : int) = + instanceCount |> AVal.constant |> ofIndexedGeometryInstancedA g - let sg = Sg.VertexAttributeApplicator(vertexAttributes, Sg.RenderNode(call, g.Mode)) :> ISg + /// Creates a draw call from the given indexed geometry. + let ofIndexedGeometry (g : IndexedGeometry) = + ofIndexedGeometryInstanced g 1 + /// Creates a draw call, supplying the given transformations as per-instance attributes + /// DefaultSemantic.InstanceTrafo and DefaultSemantic.InstanceTrafoInv. + let instancedGeometry (trafos : aval) (g : IndexedGeometry) = let sg = - if index <> null then - Sg.VertexIndexApplicator(BufferView.ofArray index, sg) :> ISg - else - sg + trafos + |> AVal.mapNonAdaptive Array.length + |> ofIndexedGeometryInstancedA g + + let forward, backward = Caching.buffersOfTrafos trafos - let view = Caching.bufferOfTrafos trafos - Sg.InstanceAttributeApplicator([DefaultSemantic.InstanceTrafo, view] |> Map.ofList, sg) :> ISg + Sg.InstanceAttributeApplicator([ + DefaultSemantic.InstanceTrafo, forward + DefaultSemantic.InstanceTrafoInv, backward + ] |> Map.ofList, sg) :> ISg // ================================================================================================================ // Bounding boxes