diff --git a/sources/core/Stride.Core/Collections/IndexingDictionary.cs b/sources/core/Stride.Core/Collections/IndexingDictionary.cs index 15c7816770..f35b088a6c 100644 --- a/sources/core/Stride.Core/Collections/IndexingDictionary.cs +++ b/sources/core/Stride.Core/Collections/IndexingDictionary.cs @@ -16,7 +16,7 @@ namespace Stride.Core.Collections; [DataSerializer(typeof(IndexingDictionarySerializer<>), Mode = DataSerializerGenericMode.GenericArguments)] public class IndexingDictionary : IDictionary where T : class { - private readonly FastList items = []; + private readonly List items = []; private List? keys; private List? values; diff --git a/sources/core/Stride.Core/Threading/Dispatcher.cs b/sources/core/Stride.Core/Threading/Dispatcher.cs index 52c4ec18f5..69e1c712d6 100644 --- a/sources/core/Stride.Core/Threading/Dispatcher.cs +++ b/sources/core/Stride.Core/Threading/Dispatcher.cs @@ -345,6 +345,7 @@ public static void Sort(ConcurrentCollector collection, IComparer compa Sort(collection.Items, 0, collection.Count, comparer); } + [Obsolete("This method will be removed in the future alongside FastList. We will have an alternative using Span which you will be able to fallback to.")] public static void Sort(FastList collection, IComparer comparer) { Sort(collection.Items, 0, collection.Count, comparer); diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EditorGameLightProbeGizmoService.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EditorGameLightProbeGizmoService.cs index 13b91a184c..61eb8c7888 100644 --- a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EditorGameLightProbeGizmoService.cs +++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EditorGameLightProbeGizmoService.cs @@ -79,7 +79,7 @@ public Task UpdateLightProbeCoefficients() } /// - public Task>> RequestLightProbesStep() + public Task>> RequestLightProbesStep() { return editor.Controller.InvokeAsync(() => { @@ -89,7 +89,7 @@ public Task>> RequestLightProbesStep() // Note: we only process first LightProbeProcessor var runtimeData = game.SceneSystem.SceneInstance.GetProcessor()?.VisibilityGroup.Tags.Get(LightProbeRenderer.CurrentLightProbes); if (runtimeData == null) - return new Dictionary>(); + return new Dictionary>(); var editorCompositor = game.EditorSceneSystem.GraphicsCompositor.Game; try diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Services/IEditorGameLightProbeService.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Services/IEditorGameLightProbeService.cs index 704d552a8f..15c64ec4fa 100644 --- a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Services/IEditorGameLightProbeService.cs +++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Services/IEditorGameLightProbeService.cs @@ -27,7 +27,7 @@ public interface IEditorGameLightProbeService : IEditorGameViewModelService /// /// This won't reset light probe coefficients. /// - Task>> RequestLightProbesStep(); + Task>> RequestLightProbesStep(); /// /// Transfers light probes coefficients by calling (from to ). diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/ViewModels/EditorLightingViewModel.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/ViewModels/EditorLightingViewModel.cs index e1448f2844..01ac450327 100644 --- a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/ViewModels/EditorLightingViewModel.cs +++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/ViewModels/EditorLightingViewModel.cs @@ -5,19 +5,18 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Stride.Core.Assets.Editor.Services; +using System.Collections.Generic; using Stride.Core.Annotations; -using Stride.Core.Collections; using Stride.Core.Extensions; using Stride.Core.Mathematics; using Stride.Core.Presentation.Commands; using Stride.Core.Presentation.Services; +using Stride.Core.Presentation.ViewModels; using Stride.Assets.Presentation.AssetEditors.EntityHierarchyEditor.Services; using Stride.Assets.Presentation.AssetEditors.GameEditor.Services; using Stride.Engine; using Stride.Graphics; using Stride.Rendering.LightProbes; -using Stride.Core.Presentation.ViewModels; namespace Stride.Assets.Presentation.AssetEditors.EntityHierarchyEditor.ViewModels { @@ -71,7 +70,7 @@ private async Task RebuildLightProbes(int bounces) { // Find this light probe in Quantum var assetNode = editor.NodeContainer.GetOrCreateNode(lightProbe); - var zeroCoefficients = new FastList(); + var zeroCoefficients = new List(); for (int i = 0; i < LightProbeGenerator.LambertHamonicOrder * LightProbeGenerator.LambertHamonicOrder; ++i) zeroCoefficients.Add(default(Color3)); assetNode[nameof(LightProbeComponent.Coefficients)].Update(zeroCoefficients); diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightProbeGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightProbeGizmo.cs index 2a873d7788..387aff27e6 100644 --- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightProbeGizmo.cs +++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightProbeGizmo.cs @@ -1,12 +1,12 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; +using System.Runtime.InteropServices; using Stride.Core.Mathematics; using Stride.Assets.Presentation.AssetEditors.EntityHierarchyEditor.Game; using Stride.Engine; using Stride.Engine.Gizmos; using Stride.Extensions; -using Stride.Graphics; using Stride.Graphics.GeometricPrimitives; using Stride.Rendering; using Stride.Rendering.LightProbes; @@ -77,7 +77,10 @@ public override void Update() base.Update(); if (Component.Coefficients != null) - lightProbeMaterial.Passes[0].Parameters.Set(ComputeSphericalHarmonicsKeys.SphericalColors, Component.Coefficients.Count, ref Component.Coefficients.Items[0]); + { + var coefficientsSpan = CollectionsMarshal.AsSpan(Component.Coefficients); + lightProbeMaterial.Passes[0].Parameters.Set(ComputeSphericalHarmonicsKeys.SphericalColors, Component.Coefficients.Count, ref coefficientsSpan[0]); + } } class ComputeSphericalHarmonics : ComputeValueBase, IComputeColor diff --git a/sources/engine/Stride.Assets.Models/AnimationAssetCompiler.cs b/sources/engine/Stride.Assets.Models/AnimationAssetCompiler.cs index 6061b55fed..e317733f48 100644 --- a/sources/engine/Stride.Assets.Models/AnimationAssetCompiler.cs +++ b/sources/engine/Stride.Assets.Models/AnimationAssetCompiler.cs @@ -220,7 +220,7 @@ private AnimationClip SubtractAnimations(AnimationClip baseAnimation, AnimationC var resultEvaluator = animationBlender.CreateEvaluator(resultAnimation); - var animationOperations = new FastList(); + var animationOperations = new List(); // Perform animation blending for each frame and upload results in a new animation // Note that it does a simple per-frame sampling, so animation discontinuities will be lost. diff --git a/sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs b/sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs index bf7b2b9e50..299d2cf132 100644 --- a/sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs +++ b/sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using Stride.Core.BuildEngine; using Stride.Core.Collections; using Stride.Core.Extensions; @@ -158,7 +159,7 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan var animationKeys = animationKeysSet.ToList(); animationKeys.Sort(); - var animationOperations = new FastList(); + var animationOperations = new List(); var combinedAnimationClip = new AnimationClip(); @@ -241,11 +242,12 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan { // Translate node with parent 0 using PivotPosition var keyFrames = ((AnimationCurve)curve).KeyFrames; - for (int i = 0; i < keyFrames.Count; ++i) + var keyFramesSpan = CollectionsMarshal.AsSpan(keyFrames); + for (int i = 0; i < keyFramesSpan.Length; ++i) { if (parentNodeIndex == 0) - keyFrames.Items[i].Value -= PivotPosition; - keyFrames.Items[i].Value *= ScaleImport; + keyFramesSpan[i].Value -= PivotPosition; + keyFramesSpan[i].Value *= ScaleImport; } } animationClip.AddCurve($"[ModelComponent.Key].Skeleton.NodeTransformations[{skeletonMapping.SourceToTarget[nodeIndex]}]." + channelName, curve); diff --git a/sources/engine/Stride.Engine.Tests/TestBowyerWatsonTetrahedralization.cs b/sources/engine/Stride.Engine.Tests/TestBowyerWatsonTetrahedralization.cs index daced12af9..bc17d2d52a 100644 --- a/sources/engine/Stride.Engine.Tests/TestBowyerWatsonTetrahedralization.cs +++ b/sources/engine/Stride.Engine.Tests/TestBowyerWatsonTetrahedralization.cs @@ -15,7 +15,7 @@ public class TestBowyerWatsonTetrahedralization public void TestCube() { // Build cube from (0,0,0) to (1,1,1) - var positions = new FastList(); + var positions = new List(); for (int i = 0; i < 8; ++i) { positions.Add(new Vector3 diff --git a/sources/engine/Stride.Engine/Animations/AnimationBlender.cs b/sources/engine/Stride.Engine/Animations/AnimationBlender.cs index 51e0e47bae..d1a71e01da 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationBlender.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationBlender.cs @@ -294,13 +294,13 @@ public static unsafe void Blend(CoreAnimationOperation blendOperation, float ble /// /// The animation operations to perform. /// The optional result (if not null, it expects the final stack to end up with this element). - public void Compute(FastList animationOperations, ref AnimationClipResult result) + public void Compute(List animationOperations, ref AnimationClipResult result) { // Clear animation stack animationStack.Clear(); // Apply first operation (should be a push), directly into result (considered first item in the stack) - var animationOperation0 = animationOperations.Items[0]; + var animationOperation0 = animationOperations[0]; if (animationOperation0.Type != AnimationOperationType.Push) throw new InvalidOperationException("First operation should be a push"); @@ -335,7 +335,7 @@ public void Compute(FastList animationOperations, ref Animat for (int index = 1; index < animationOperations.Count; index++) { - var animationOperation = animationOperations.Items[index]; + var animationOperation = animationOperations[index]; ApplyAnimationOperation(ref animationOperation); } diff --git a/sources/engine/Stride.Engine/Animations/AnimationCurve.cs b/sources/engine/Stride.Engine/Animations/AnimationCurve.cs index c25caed705..25e15ed83d 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationCurve.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationCurve.cs @@ -85,7 +85,7 @@ public class AnimationCurve : AnimationCurve /// /// The key frames. /// - public FastList> KeyFrames { get; set; } + public List> KeyFrames { get; set; } /// [DataMemberIgnore] @@ -107,7 +107,7 @@ public override IReadOnlyList Keys public AnimationCurve() { - KeyFrames = new FastList>(); + KeyFrames = []; } /// @@ -157,7 +157,7 @@ internal override AnimationData CreateOptimizedData(IEnumerable public override void ShiftKeys(CompressedTimeSpan shiftTimeSpan) { - var shiftedKeyFrames = new FastList>(); + var shiftedKeyFrames = new List>(); foreach (var keyFrameData in KeyFrames) { diff --git a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectBlittableGroup.cs b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectBlittableGroup.cs index 25ee0a09f6..65ab6883bc 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectBlittableGroup.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectBlittableGroup.cs @@ -16,7 +16,7 @@ protected override unsafe void ProcessChannel(ref Channel channel, CompressedTim var keyFrames = channel.Curve.KeyFrames; var currentIndex = channel.CurrentIndex; - Unsafe.AsRef((void*)(location + channel.Offset)) = keyFrames.Items[currentIndex].Value; + Unsafe.AsRef((void*)(location + channel.Offset)) = keyFrames[currentIndex].Value; } } } diff --git a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectFloatGroup.cs b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectFloatGroup.cs index e1d0fdcedb..1db40c060d 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectFloatGroup.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectFloatGroup.cs @@ -3,12 +3,13 @@ using System; using Stride.Core.Mathematics; +using System.Runtime.InteropServices; namespace Stride.Animations { public class AnimationCurveEvaluatorDirectFloatGroup : AnimationCurveEvaluatorDirectBlittableGroupBase { - protected unsafe override void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) + protected override unsafe void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) { SetTime(ref channel, newTime); @@ -16,7 +17,7 @@ protected unsafe override void ProcessChannel(ref Channel channel, CompressedTim var currentIndex = channel.CurrentIndex; var keyFrames = channel.Curve.KeyFrames; - var keyFramesItems = keyFrames.Items; + var keyFramesItems = CollectionsMarshal.AsSpan(keyFrames); var keyFramesCount = keyFrames.Count; // Extract data diff --git a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectGroup.cs b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectGroup.cs index 66e39b2391..131477a5c6 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectGroup.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectGroup.cs @@ -2,6 +2,7 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. #pragma warning disable SA1402 // File may only contain a single class using System; +using System.Runtime.InteropServices; using Stride.Core.Collections; using Stride.Core.Mathematics; using Stride.Updater; @@ -66,24 +67,24 @@ protected static void SetTime(ref Channel channel, CompressedTimeSpan newTime) var currentIndex = channel.CurrentIndex; var keyFrames = channel.Curve.KeyFrames; - var keyFramesItems = keyFrames.Items; + var keyFramesSpan = CollectionsMarshal.AsSpan(keyFrames); var keyFramesCount = keyFrames.Count; if (newTime > currentTime) { - while (currentIndex + 1 < keyFramesCount - 1 && newTime >= keyFramesItems[currentIndex + 1].Time) + while (currentIndex + 1 < keyFramesCount - 1 && newTime >= keyFramesSpan[currentIndex + 1].Time) { ++currentIndex; } } - else if (newTime <= keyFramesItems[0].Time) + else if (newTime <= keyFramesSpan[0].Time) { // Special case: fast rewind to beginning of animation currentIndex = 0; } else // newTime < currentTime { - while (currentIndex - 1 >= 0 && newTime < keyFramesItems[currentIndex].Time) + while (currentIndex - 1 >= 0 && newTime < keyFramesSpan[currentIndex].Time) { --currentIndex; } @@ -139,7 +140,7 @@ private void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, Upd var keyFrames = channel.Curve.KeyFrames; var currentIndex = channel.CurrentIndex; - objects[channel.Offset].Value = keyFrames.Items[currentIndex].Value; + objects[channel.Offset].Value = keyFrames[currentIndex].Value; } } } diff --git a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectQuaternionGroup.cs b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectQuaternionGroup.cs index a9ebd09b1d..b58c348d94 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectQuaternionGroup.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectQuaternionGroup.cs @@ -3,12 +3,13 @@ using System; using Stride.Core.Mathematics; +using System.Runtime.InteropServices; namespace Stride.Animations { public class AnimationCurveEvaluatorDirectQuaternionGroup : AnimationCurveEvaluatorDirectBlittableGroupBase { - protected unsafe override void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) + protected override unsafe void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) { SetTime(ref channel, newTime); @@ -16,7 +17,7 @@ protected unsafe override void ProcessChannel(ref Channel channel, CompressedTim var currentIndex = channel.CurrentIndex; var keyFrames = channel.Curve.KeyFrames; - var keyFramesItems = keyFrames.Items; + var keyFramesItems = CollectionsMarshal.AsSpan(keyFrames); var keyFramesCount = keyFrames.Count; // Extract data diff --git a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector3Group.cs b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector3Group.cs index edca2c17fe..b1026e760d 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector3Group.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector3Group.cs @@ -3,12 +3,13 @@ using System; using Stride.Core.Mathematics; +using System.Runtime.InteropServices; namespace Stride.Animations { public class AnimationCurveEvaluatorDirectVector3Group : AnimationCurveEvaluatorDirectBlittableGroupBase { - protected unsafe override void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) + protected override unsafe void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) { SetTime(ref channel, newTime); @@ -16,7 +17,7 @@ protected unsafe override void ProcessChannel(ref Channel channel, CompressedTim var currentIndex = channel.CurrentIndex; var keyFrames = channel.Curve.KeyFrames; - var keyFramesItems = keyFrames.Items; + var keyFramesItems = CollectionsMarshal.AsSpan(keyFrames); var keyFramesCount = keyFrames.Count; // Extract data diff --git a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector4Group.cs b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector4Group.cs index dd6da282db..574c3838b5 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector4Group.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector4Group.cs @@ -2,12 +2,13 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using Stride.Core.Mathematics; +using System.Runtime.InteropServices; namespace Stride.Animations { public class AnimationCurveEvaluatorDirectVector4Group : AnimationCurveEvaluatorDirectBlittableGroupBase { - protected unsafe override void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) + protected override unsafe void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) { SetTime(ref channel, newTime); @@ -15,7 +16,7 @@ protected unsafe override void ProcessChannel(ref Channel channel, CompressedTim var currentIndex = channel.CurrentIndex; var keyFrames = channel.Curve.KeyFrames; - var keyFramesItems = keyFrames.Items; + var keyFramesItems = CollectionsMarshal.AsSpan(keyFrames); var keyFramesCount = keyFrames.Count; // Extract data diff --git a/sources/engine/Stride.Engine/Animations/AnimationProcessor.cs b/sources/engine/Stride.Engine/Animations/AnimationProcessor.cs index bf642bdf87..82965c8a5e 100644 --- a/sources/engine/Stride.Engine/Animations/AnimationProcessor.cs +++ b/sources/engine/Stride.Engine/Animations/AnimationProcessor.cs @@ -13,7 +13,7 @@ namespace Stride.Animations { public class AnimationProcessor : EntityProcessor { - private readonly ConcurrentPool> animationOperationPool = new ConcurrentPool>(() => new FastList()); + private readonly ConcurrentPool> animationOperationPool = new ConcurrentPool>(() => []); public AnimationProcessor() { diff --git a/sources/engine/Stride.Engine/Animations/ComputeAnimationCurve.cs b/sources/engine/Stride.Engine/Animations/ComputeAnimationCurve.cs index 19c5a4a4cf..541dc1075f 100644 --- a/sources/engine/Stride.Engine/Animations/ComputeAnimationCurve.cs +++ b/sources/engine/Stride.Engine/Animations/ComputeAnimationCurve.cs @@ -25,7 +25,7 @@ public abstract class ComputeAnimationCurve : Comparer>, public TrackingCollection> KeyFrames { get; set; } = new TrackingCollection>(); // TODO This list will become AnimationCurve - private FastList> sortedKeys = new FastList>(); + private List> sortedKeys = []; private int framesCount = 0; private bool HasChanged() diff --git a/sources/engine/Stride.Engine/Engine/AnimationComponent.cs b/sources/engine/Stride.Engine/Engine/AnimationComponent.cs index d1fb246e23..8928278d37 100644 --- a/sources/engine/Stride.Engine/Engine/AnimationComponent.cs +++ b/sources/engine/Stride.Engine/Engine/AnimationComponent.cs @@ -211,6 +211,6 @@ public Task Ended(PlayingAnimation animation) public interface IBlendTreeBuilder { - void BuildBlendTree(FastList animationList); + void BuildBlendTree(List animationList); } } diff --git a/sources/engine/Stride.Engine/Engine/EntityProcessor.cs b/sources/engine/Stride.Engine/Engine/EntityProcessor.cs index b546f88883..8d524bf2f9 100644 --- a/sources/engine/Stride.Engine/Engine/EntityProcessor.cs +++ b/sources/engine/Stride.Engine/Engine/EntityProcessor.cs @@ -218,9 +218,9 @@ internal bool IsDependentOnComponentType(TypeInfo type) /// public abstract class EntityProcessor : EntityProcessor where TData : class where TComponent : EntityComponent { - protected readonly Dictionary ComponentDatas = new Dictionary(); - private readonly HashSet reentrancyCheck = new HashSet(); - private readonly FastList checkRequiredTypes = new FastList(); + protected readonly Dictionary ComponentDatas = []; + private readonly HashSet reentrancyCheck = []; + private readonly List checkRequiredTypes = []; protected EntityProcessor([NotNull] params Type[] requiredAdditionalTypes) : base(typeof(TComponent), requiredAdditionalTypes) @@ -358,7 +358,7 @@ private bool EntityMatch(Entity entity) var componentType = components[i].GetType().GetTypeInfo(); for (var j = checkRequiredTypes.Count - 1; j >= 0; j--) { - if (checkRequiredTypes.Items[j].IsAssignableFrom(componentType)) + if (checkRequiredTypes[j].IsAssignableFrom(componentType)) { checkRequiredTypes.RemoveAt(j); diff --git a/sources/engine/Stride.Engine/Engine/LightProbeComponent.cs b/sources/engine/Stride.Engine/Engine/LightProbeComponent.cs index 4a9ca77c03..8504aa1c52 100644 --- a/sources/engine/Stride.Engine/Engine/LightProbeComponent.cs +++ b/sources/engine/Stride.Engine/Engine/LightProbeComponent.cs @@ -1,9 +1,9 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +using System.Collections.Generic; using Stride.Core; using Stride.Core.Annotations; -using Stride.Core.Collections; using Stride.Core.Mathematics; using Stride.Engine.Design; using Stride.Rendering.LightProbes; @@ -19,6 +19,6 @@ public class LightProbeComponent : EntityComponent { [Display(Browsable = false)] [NonIdentifiableCollectionItems] - public FastList Coefficients { get; set; } + public List Coefficients { get; set; } } } diff --git a/sources/engine/Stride.Engine/Engine/SceneInstance.cs b/sources/engine/Stride.Engine/Engine/SceneInstance.cs index cab3b67ca5..6b3b8de2a5 100644 --- a/sources/engine/Stride.Engine/Engine/SceneInstance.cs +++ b/sources/engine/Stride.Engine/Engine/SceneInstance.cs @@ -135,7 +135,7 @@ private void Add(Scene scene) { if (scene.Entities.Count > 0) { - var entitiesToAdd = new FastList(); + var entitiesToAdd = new List(); // Reverse order, we're adding and removing from the tail to // avoid forcing the list to move all items when removing at [0] for (int i = scene.Entities.Count -1; i >= 0; i-- ) @@ -166,7 +166,7 @@ void DealWithTempChanges(object sender, TrackingCollectionChangedEventArgs e) if (scene.Children.Count > 0) { - var scenesToAdd = new FastList(); + var scenesToAdd = new List(); // Reverse order, we're adding and removing from the tail to // avoid forcing the list to move all items when removing at [0] for (int i = scene.Children.Count - 1; i >= 0; i--) diff --git a/sources/engine/Stride.Engine/Rendering/Compositing/ForwardRenderer.cs b/sources/engine/Stride.Engine/Rendering/Compositing/ForwardRenderer.cs index 9be34ed187..05abe1fd6f 100644 --- a/sources/engine/Stride.Engine/Rendering/Compositing/ForwardRenderer.cs +++ b/sources/engine/Stride.Engine/Rendering/Compositing/ForwardRenderer.cs @@ -7,7 +7,6 @@ using System.Runtime.InteropServices; using Stride.Core; using Stride.Core.Annotations; -using Stride.Core.Collections; using Stride.Core.Diagnostics; using Stride.Core.Mathematics; using Stride.Core.Storage; @@ -39,8 +38,8 @@ public partial class ForwardRenderer : SceneRendererBase, ISharedRenderer private readonly Logger logger = GlobalLogger.GetLogger(nameof(ForwardRenderer)); - private readonly FastList currentRenderTargets = new FastList(); - private readonly FastList currentRenderTargetsNonMSAA = new FastList(); + private readonly List currentRenderTargets = []; + private readonly List currentRenderTargetsNonMSAA = []; private Texture currentDepthStencil; private Texture currentDepthStencilNonMSAA; @@ -472,7 +471,17 @@ protected static PixelFormat ComputeNonMSAADepthFormat(PixelFormat format) private void ResolveMSAA(RenderDrawContext drawContext) { // Resolve render targets - currentRenderTargetsNonMSAA.Resize(currentRenderTargets.Count, false); + if (currentRenderTargetsNonMSAA.Count < currentRenderTargets.Count) + { + currentRenderTargetsNonMSAA.EnsureCapacity(currentRenderTargets.Count); + while (currentRenderTargetsNonMSAA.Count != currentRenderTargets.Count) + currentRenderTargetsNonMSAA.Add(null); + } + else if (currentRenderTargetsNonMSAA.Count > currentRenderTargets.Count) + { + currentRenderTargetsNonMSAA.RemoveRange(currentRenderTargets.Count, currentRenderTargetsNonMSAA.Count - currentRenderTargets.Count); + } + for (int index = 0; index < currentRenderTargets.Count; index++) { var input = currentRenderTargets[index]; @@ -597,7 +606,7 @@ protected virtual void DrawView(RenderContext context, RenderDrawContext drawCon { // Run post effects // Note: OpaqueRenderStage can't be null otherwise colorTargetIndex would be -1 - PostEffects.Draw(drawContext, OpaqueRenderStage.OutputValidator, renderTargets.Items, depthStencil, viewOutputTarget); + PostEffects.Draw(drawContext, OpaqueRenderStage.OutputValidator, CollectionsMarshal.AsSpan(renderTargets), depthStencil, viewOutputTarget); } else { @@ -687,7 +696,7 @@ protected override void DrawCore(RenderContext context, RenderDrawContext drawCo } } - drawContext.CommandList.SetRenderTargets(currentDepthStencil, currentRenderTargets.Count, currentRenderTargets.Items); + drawContext.CommandList.SetRenderTargets(currentDepthStencil, currentRenderTargets.Count, CollectionsMarshal.AsSpan(currentRenderTargets)); if (!hasPostEffects && !isWindowsMixedReality) // need to change the viewport between each eye { @@ -746,7 +755,7 @@ protected override void DrawCore(RenderContext context, RenderDrawContext drawCo using (drawContext.PushRenderTargetsAndRestore()) { - drawContext.CommandList.SetRenderTargets(currentDepthStencil, currentRenderTargets.Count, currentRenderTargets.Items); + drawContext.CommandList.SetRenderTargets(currentDepthStencil, currentRenderTargets.Count, CollectionsMarshal.AsSpan(currentRenderTargets)); // Clear render target and depth stencil Clear?.Draw(drawContext); @@ -840,7 +849,16 @@ private void PrepareRenderTargets(RenderDrawContext drawContext, Texture outputR var renderTargets = OpaqueRenderStage.OutputValidator.RenderTargets; - currentRenderTargets.Resize(renderTargets.Count, false); + if (currentRenderTargets.Count < renderTargets.Count) + { + currentRenderTargets.EnsureCapacity(renderTargets.Count); + while (currentRenderTargets.Count != renderTargets.Count) + currentRenderTargets.Add(null); + } + else if (currentRenderTargets.Count > renderTargets.Count) + { + currentRenderTargets.RemoveRange(renderTargets.Count, currentRenderTargets.Count - renderTargets.Count); + } for (int index = 0; index < renderTargets.Count; index++) { diff --git a/sources/engine/Stride.Engine/Rendering/LightProbes/LightProbeGenerator.cs b/sources/engine/Stride.Engine/Rendering/LightProbes/LightProbeGenerator.cs index a7ecf13fa6..ca06b0e15e 100644 --- a/sources/engine/Stride.Engine/Rendering/LightProbes/LightProbeGenerator.cs +++ b/sources/engine/Stride.Engine/Rendering/LightProbes/LightProbeGenerator.cs @@ -26,7 +26,7 @@ public static class LightProbeGenerator { public const int LambertHamonicOrder = 3; - public static Dictionary> GenerateCoefficients(ISceneRendererContext context) + public static Dictionary> GenerateCoefficients(ISceneRendererContext context) { using (var cubemapRenderer = new CubemapSceneRenderer(context, 256)) { @@ -40,7 +40,7 @@ public static Dictionary> GenerateCoeffici RadianceMap = cubeTexture, }; - var lightProbesCoefficients = new Dictionary>(); + var lightProbesCoefficients = new Dictionary>(); using (cubemapRenderer.DrawContext.PushRenderTargetsAndRestore()) { @@ -68,7 +68,7 @@ public static Dictionary> GenerateCoeffici lambertFiltering.Draw(cubemapRenderer.DrawContext); var coefficients = lambertFiltering.PrefilteredLambertianSH.Coefficients; - var lightProbeCoefficients = new FastList(); + var lightProbeCoefficients = new List(); for (int i = 0; i < coefficients.Length; i++) { lightProbeCoefficients.Add(coefficients[i] * SphericalHarmonics.BaseCoefficients[i]); @@ -113,13 +113,13 @@ public static unsafe void UpdateCoefficients(LightProbeRuntimeData runtimeData) } } - public static unsafe LightProbeRuntimeData GenerateRuntimeData(FastList lightProbes) + public static unsafe LightProbeRuntimeData GenerateRuntimeData(List lightProbes) { // TODO: Better check: coplanar, etc... (maybe the check inside BowyerWatsonTetrahedralization might be enough -- tetrahedron won't be in positive order) if (lightProbes.Count < 4) throw new InvalidOperationException("Can't generate lightprobes if less than 4 of them exists."); - var lightProbePositions = new FastList(); + var lightProbePositions = new List(); var lightProbeCoefficients = new Color3[lightProbes.Count * LambertHamonicOrder * LambertHamonicOrder]; var destColors = lightProbeCoefficients.AsSpan(); #if false diff --git a/sources/engine/Stride.Engine/Rendering/LightProbes/LightProbeProcessor.cs b/sources/engine/Stride.Engine/Rendering/LightProbes/LightProbeProcessor.cs index c6ce4120f6..a67d69c1b8 100644 --- a/sources/engine/Stride.Engine/Rendering/LightProbes/LightProbeProcessor.cs +++ b/sources/engine/Stride.Engine/Rendering/LightProbes/LightProbeProcessor.cs @@ -2,9 +2,7 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; -using Stride.Core.Collections; -using Stride.Core.Mathematics; -using Stride.Core.Storage; +using System.Collections.Generic; using Stride.Engine; namespace Stride.Rendering.LightProbes @@ -35,7 +33,7 @@ public void UpdateLightProbePositions() try { // Collect LightProbes - var lightProbes = new FastList(); + var lightProbes = new List(); foreach (var lightProbe in ComponentDatas) { diff --git a/sources/engine/Stride.Graphics/CommandList.cs b/sources/engine/Stride.Graphics/CommandList.cs index 530adc1269..fc6e5ccd5d 100644 --- a/sources/engine/Stride.Graphics/CommandList.cs +++ b/sources/engine/Stride.Graphics/CommandList.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +using System; using System.Collections.Generic; using Stride.Core.Mathematics; @@ -299,7 +300,7 @@ public void SetRenderTargets(Texture[] renderTargetViews) /// The number of render target in . /// A set of render target views to bind. /// renderTargetViews - public void SetRenderTargets(Texture depthStencilView, int renderTargetViewCount, Texture[] renderTargetViews) + public void SetRenderTargets(Texture depthStencilView, int renderTargetViewCount, Span renderTargetViews) { depthStencilBuffer = depthStencilView; diff --git a/sources/engine/Stride.Graphics/Direct3D/SwapChainGraphicsPresenter.Direct3D.cs b/sources/engine/Stride.Graphics/Direct3D/SwapChainGraphicsPresenter.Direct3D.cs index d7e06d3ead..711e5622cf 100644 --- a/sources/engine/Stride.Graphics/Direct3D/SwapChainGraphicsPresenter.Direct3D.cs +++ b/sources/engine/Stride.Graphics/Direct3D/SwapChainGraphicsPresenter.Direct3D.cs @@ -23,7 +23,7 @@ #if STRIDE_GRAPHICS_API_DIRECT3D using System; -using System.Reflection; +using System.Collections.Generic; using SharpDX; using SharpDX.DXGI; using SharpDX.Mathematics.Interop; @@ -333,9 +333,9 @@ protected override void ResizeDepthStencilBuffer(int width, int height, PixelFor /// /// Specified parent texture /// A list of the children textures which were destroyed - private FastList DestroyChildrenTextures(Texture parentTexture) + private List DestroyChildrenTextures(Texture parentTexture) { - var fastList = new FastList(); + var fastList = new List(); var resources = GraphicsDevice.Resources; lock (resources) { diff --git a/sources/engine/Stride.Graphics/Effects/Effect.cs b/sources/engine/Stride.Graphics/Effects/Effect.cs index 2595aff503..9cf7c0e9ae 100644 --- a/sources/engine/Stride.Graphics/Effects/Effect.cs +++ b/sources/engine/Stride.Graphics/Effects/Effect.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using Stride.Core; using Stride.Core.Mathematics; using Stride.Core.Serialization; @@ -10,7 +11,6 @@ using Stride.Core.Storage; using Stride.Rendering; using Stride.Shaders; -using Stride.Shaders.Compiler; namespace Stride.Graphics { @@ -104,12 +104,14 @@ private void Initialize() private static void PrepareReflection(EffectReflection reflection) { + var resourceBindingsSpan = CollectionsMarshal.AsSpan(reflection.ResourceBindings); + // prepare resource bindings used internally - for (int i = 0; i < reflection.ResourceBindings.Count; i++) + for (int i = 0; i < resourceBindingsSpan.Length; i++) { // it is fine if multiple threads do this at the same time (same result) // we use ref to avoid reassigning to the list (which cause a Collection modified during enumeration exception) - UpdateResourceBindingKey(ref reflection.ResourceBindings.Items[i]); + UpdateResourceBindingKey(ref resourceBindingsSpan[i]); } foreach (var constantBuffer in reflection.ConstantBuffers) { diff --git a/sources/engine/Stride.Graphics/OpenGL/EffectProgram.OpenGL.cs b/sources/engine/Stride.Graphics/OpenGL/EffectProgram.OpenGL.cs index cf52ce4696..f25c503db8 100644 --- a/sources/engine/Stride.Graphics/OpenGL/EffectProgram.OpenGL.cs +++ b/sources/engine/Stride.Graphics/OpenGL/EffectProgram.OpenGL.cs @@ -503,7 +503,7 @@ private void CreateReflection(EffectReflection effectReflection, ShaderStage sta /// The index in the list. /// The list of bindings. /// The new index of the data. - private static int GetReflexionIndex(EffectResourceBindingDescription data, int index, FastList bindings) + private static int GetReflexionIndex(EffectResourceBindingDescription data, int index, List bindings) { if (data.SlotCount != 0) { diff --git a/sources/engine/Stride.Physics.Tests/CharacterTest.cs b/sources/engine/Stride.Physics.Tests/CharacterTest.cs index 04df8b453f..e2bd6eb049 100644 --- a/sources/engine/Stride.Physics.Tests/CharacterTest.cs +++ b/sources/engine/Stride.Physics.Tests/CharacterTest.cs @@ -1,8 +1,8 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System.Linq; +using System.Collections.Generic; using Xunit; -using Stride.Core.Collections; using Stride.Core.Mathematics; using Stride.Engine; @@ -30,7 +30,7 @@ public static bool ScreenPositionToWorldPositionRaycast(Vector2 screenPos, Camer var vectorFar = Vector3.Transform(sPos, invViewProj); vectorFar /= vectorFar.W; - var result = new FastList(); + var result = new List(); simulation.RaycastPenetrating(vectorNear.XYZ(), vectorFar.XYZ(), result); foreach (var hitResult in result) { diff --git a/sources/engine/Stride.Physics.Tests/ColliderShapesTest.cs b/sources/engine/Stride.Physics.Tests/ColliderShapesTest.cs index 912a0ba53d..8a6f482903 100644 --- a/sources/engine/Stride.Physics.Tests/ColliderShapesTest.cs +++ b/sources/engine/Stride.Physics.Tests/ColliderShapesTest.cs @@ -1,8 +1,8 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System.Linq; +using System.Collections.Generic; using Xunit; -using Stride.Core.Collections; using Stride.Core.Mathematics; using Stride.Engine; @@ -30,7 +30,7 @@ public static bool ScreenPositionToWorldPositionRaycast(Vector2 screenPos, Camer var vectorFar = Vector3.Transform(sPos, invViewProj); vectorFar /= vectorFar.W; - var result = new FastList(); + var result = new List(); simulation.RaycastPenetrating(vectorNear.XYZ(), vectorFar.XYZ(), result); foreach (var hitResult in result) { diff --git a/sources/engine/Stride.Physics.Tests/SkinnedTest.cs b/sources/engine/Stride.Physics.Tests/SkinnedTest.cs index 03753b5333..71ce2394c5 100644 --- a/sources/engine/Stride.Physics.Tests/SkinnedTest.cs +++ b/sources/engine/Stride.Physics.Tests/SkinnedTest.cs @@ -1,8 +1,8 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System.Linq; +using System.Collections.Generic; using Xunit; -using Stride.Core.Collections; using Stride.Core.Mathematics; using Stride.Engine; @@ -30,7 +30,7 @@ public static bool ScreenPositionToWorldPositionRaycast(Vector2 screenPos, Camer var vectorFar = Vector3.Transform(sPos, invViewProj); vectorFar /= vectorFar.W; - var result = new FastList(); + var result = new List(); simulation.RaycastPenetrating(vectorNear.XYZ(), vectorFar.XYZ(), result); foreach (var hitResult in result) { diff --git a/sources/engine/Stride.Physics/Elements/RigidbodyComponent.cs b/sources/engine/Stride.Physics/Elements/RigidbodyComponent.cs index 24a200791d..e7593b26a9 100644 --- a/sources/engine/Stride.Physics/Elements/RigidbodyComponent.cs +++ b/sources/engine/Stride.Physics/Elements/RigidbodyComponent.cs @@ -365,7 +365,7 @@ protected override void OnDetach() return; //Remove constraints safely - var toremove = new FastList(); + var toremove = new List(); foreach (var c in LinkedConstraints) { toremove.Add(c); diff --git a/sources/engine/Stride.Physics/Engine/PhysicsConstraintProcessor.cs b/sources/engine/Stride.Physics/Engine/PhysicsConstraintProcessor.cs index 7dae090ae0..dc04fe17ca 100644 --- a/sources/engine/Stride.Physics/Engine/PhysicsConstraintProcessor.cs +++ b/sources/engine/Stride.Physics/Engine/PhysicsConstraintProcessor.cs @@ -2,8 +2,8 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; +using System.Collections.Generic; using Stride.Core.Annotations; -using Stride.Core.Collections; using Stride.Core.Diagnostics; using Stride.Engine; using Stride.Games; @@ -14,7 +14,7 @@ public class PhysicsConstraintProcessor : EntityProcessor detachedComponents = new FastList(); + private readonly List detachedComponents = []; public PhysicsConstraintProcessor() { diff --git a/sources/engine/Stride.Rendering/Rendering/Compositing/RenderOutputValidator.cs b/sources/engine/Stride.Rendering/Rendering/Compositing/RenderOutputValidator.cs index c8df390072..eb7d8d7553 100644 --- a/sources/engine/Stride.Rendering/Rendering/Compositing/RenderOutputValidator.cs +++ b/sources/engine/Stride.Rendering/Rendering/Compositing/RenderOutputValidator.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Stride.Core.Collections; +using System.Runtime.InteropServices; using Stride.Graphics; using Stride.Shaders; @@ -15,7 +15,7 @@ namespace Stride.Rendering.Compositing /// public sealed class RenderOutputValidator { - private readonly FastList renderTargets = new FastList(); + private readonly List renderTargets = []; private readonly RenderStage renderStage; private int validatedTargetCount; @@ -79,7 +79,16 @@ public unsafe void EndCustomValidation() { if (validatedTargetCount < renderTargets.Count || hasChanged) { - renderTargets.Resize(validatedTargetCount, false); + if (renderTargets.Count < validatedTargetCount) + { + renderTargets.EnsureCapacity(validatedTargetCount); + while (renderTargets.Count != validatedTargetCount) + renderTargets.Add(default); + } + else if (renderTargets.Count > validatedTargetCount) + { + renderTargets.RemoveRange(validatedTargetCount, renderTargets.Count - validatedTargetCount); + } // Recalculate shader sources ShaderSource = new ShaderMixinSource(); diff --git a/sources/engine/Stride.Rendering/Rendering/Images/IPostProcessingEffects.cs b/sources/engine/Stride.Rendering/Rendering/Images/IPostProcessingEffects.cs index 3b4f4bf061..6a158eeeef 100644 --- a/sources/engine/Stride.Rendering/Rendering/Images/IPostProcessingEffects.cs +++ b/sources/engine/Stride.Rendering/Rendering/Images/IPostProcessingEffects.cs @@ -2,6 +2,7 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; +using System.Collections.Generic; using Stride.Graphics; using Stride.Rendering.Compositing; @@ -11,7 +12,7 @@ public interface IPostProcessingEffects : ISharedRenderer, IDisposable { void Collect(RenderContext context); - void Draw(RenderDrawContext drawContext, RenderOutputValidator outputValidator, Texture[] inputs, Texture inputDepthStencil, Texture outputTarget); + void Draw(RenderDrawContext drawContext, RenderOutputValidator outputValidator, Span inputs, Texture inputDepthStencil, Texture outputTarget); bool RequiresVelocityBuffer { get; } diff --git a/sources/engine/Stride.Rendering/Rendering/Images/LightShafts/LightShafts.cs b/sources/engine/Stride.Rendering/Rendering/Images/LightShafts/LightShafts.cs index ffa9019295..12a980a17e 100644 --- a/sources/engine/Stride.Rendering/Rendering/Images/LightShafts/LightShafts.cs +++ b/sources/engine/Stride.Rendering/Rendering/Images/LightShafts/LightShafts.cs @@ -482,7 +482,7 @@ private class LightShaftRenderData public LightGroupRendererDynamic GroupRenderer; public LightShaderGroupDynamic ShaderGroup; public IDirectLight Light; - public FastList RenderViews = new FastList(new RenderView[1]); + public List RenderViews = [..new RenderView[1]]; public LightShadowType ShadowType; public ILightShadowMapRenderer ShadowMapRenderer; public int UsageCounter = 0; diff --git a/sources/engine/Stride.Rendering/Rendering/Images/PostProcessingEffects.cs b/sources/engine/Stride.Rendering/Rendering/Images/PostProcessingEffects.cs index becfa42d68..5c03aadb64 100644 --- a/sources/engine/Stride.Rendering/Rendering/Images/PostProcessingEffects.cs +++ b/sources/engine/Stride.Rendering/Rendering/Images/PostProcessingEffects.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; +using System.Collections.Generic; using System.ComponentModel; using Stride.Core; using Stride.Core.Annotations; @@ -229,7 +230,7 @@ public void Collect(RenderContext context) { } - public void Draw(RenderDrawContext drawContext, RenderOutputValidator outputValidator, Texture[] inputs, Texture inputDepthStencil, Texture outputTarget) + public void Draw(RenderDrawContext drawContext, RenderOutputValidator outputValidator, Span inputs, Texture inputDepthStencil, Texture outputTarget) { var colorIndex = outputValidator.Find(); if (colorIndex < 0) diff --git a/sources/engine/Stride.Rendering/Rendering/LightProbes/BowyerWatsonTetrahedralization.cs b/sources/engine/Stride.Rendering/Rendering/LightProbes/BowyerWatsonTetrahedralization.cs index 4d30b2e36b..fa68cd9cb1 100644 --- a/sources/engine/Stride.Rendering/Rendering/LightProbes/BowyerWatsonTetrahedralization.cs +++ b/sources/engine/Stride.Rendering/Rendering/LightProbes/BowyerWatsonTetrahedralization.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; -using Stride.Core; -using Stride.Core.Collections; using Stride.Core.Mathematics; using Stride.Core.Serialization; @@ -21,15 +19,15 @@ public class BowyerWatsonTetrahedralization // TODO: Make this customizable public const float ExtrapolationDistance = 100.0f; - private readonly List badTetrahedra = new List(); - private readonly FastList holeFaces = new FastList(); - private readonly List edges = new List(); - private readonly List freeTetrahedra = new List(); + private readonly List badTetrahedra = []; + private readonly List holeFaces = []; + private readonly List edges = []; + private readonly List freeTetrahedra = []; private readonly Predicates predicates = new(); private Vector3[] vertices; - private FastList tetrahedralization; + private List tetrahedralization; public struct Result { @@ -38,8 +36,8 @@ public struct Result /// Any vertex in after this index are added automatically for boundaries. /// public int UserVertexCount; - public FastList Tetrahedra; - public FastList Faces; + public List Tetrahedra; + public List Faces; } [DataSerializer(typeof(Face.Serializer))] @@ -112,7 +110,7 @@ public Result Compute(IReadOnlyList vertices) // TODO: Another approach would be to receive a IList/Array directly and have a method GetVertexAtIndex(i) with special care for i in [vertices.Length; vertices.Length + 4[ range. this.vertices = vertices.Concat(new Vector3[4]).ToArray(); - tetrahedralization = new FastList(); + tetrahedralization = []; freeTetrahedra.Clear(); // Create super-tetrahedra that encompass everything @@ -151,52 +149,52 @@ private unsafe void GenerateExtrapolationProbes() var outerVertexNormals = new Vector3[vertices.Length]; var extraVertices = new List(); + + var tetrahedralizationSpan = CollectionsMarshal.AsSpan(tetrahedralization); // Sum normals on outer vertices - fixed (Tetrahedron* tetrahedra = tetrahedralization.Items) + for (int index = 0; index < tetrahedralizationSpan.Length; index++) { - for (int index = 0; index < tetrahedralization.Count; index++) - { - var currentTetrahedron = &tetrahedra[index]; + var currentTetrahedron = tetrahedralizationSpan[index]; - var superTetrahedronVertexCount = 0; - var superTetrahedronVertexIndex = -1; - for (int i = 0; i < 4; ++i) + var superTetrahedronVertexCount = 0; + var superTetrahedronVertexIndex = -1; + for (int i = 0; i < 4; ++i) + { + if (currentTetrahedron.Vertices[i] >= vertices.Length - 4) { - if (currentTetrahedron->Vertices[i] >= vertices.Length - 4) - { - superTetrahedronVertexCount++; - superTetrahedronVertexIndex = i; - } + superTetrahedronVertexCount++; + superTetrahedronVertexIndex = i; } + } - // One vertex at infinity, 3 inside (face) - if (superTetrahedronVertexCount == 1) - { - var vertex0 = currentTetrahedron->Vertices[(superTetrahedronVertexIndex + 1) % 4]; - var vertex1 = currentTetrahedron->Vertices[(superTetrahedronVertexIndex + 2) % 4]; - var vertex2 = currentTetrahedron->Vertices[(superTetrahedronVertexIndex + 3) % 4]; - var superTetrahedronVertex = currentTetrahedron->Vertices[superTetrahedronVertexIndex]; - - // Compute normal - Vector3 edge1, edge2, faceNormal; - Vector3.Subtract(ref vertices[vertex1], ref vertices[vertex0], out edge1); - Vector3.Subtract(ref vertices[vertex2], ref vertices[vertex0], out edge2); - Vector3.Cross(ref edge1, ref edge2, out faceNormal); - faceNormal.Normalize(); - - // Reverse it if not facing proper direction (extraVertex should be on the positive side) - var plane = new Plane(vertices[vertex0], faceNormal); - if (CollisionHelper.DistancePlanePoint(ref plane, ref vertices[superTetrahedronVertex]) < 0.0f) - faceNormal = -faceNormal; + // One vertex at infinity, 3 inside (face) + if (superTetrahedronVertexCount == 1) + { + var vertex0 = currentTetrahedron.Vertices[(superTetrahedronVertexIndex + 1) % 4]; + var vertex1 = currentTetrahedron.Vertices[(superTetrahedronVertexIndex + 2) % 4]; + var vertex2 = currentTetrahedron.Vertices[(superTetrahedronVertexIndex + 3) % 4]; + var superTetrahedronVertex = currentTetrahedron.Vertices[superTetrahedronVertexIndex]; + + // Compute normal + Vector3 edge1, edge2, faceNormal; + Vector3.Subtract(ref vertices[vertex1], ref vertices[vertex0], out edge1); + Vector3.Subtract(ref vertices[vertex2], ref vertices[vertex0], out edge2); + Vector3.Cross(ref edge1, ref edge2, out faceNormal); + faceNormal.Normalize(); + + // Reverse it if not facing proper direction (extraVertex should be on the positive side) + var plane = new Plane(vertices[vertex0], faceNormal); + if (CollisionHelper.DistancePlanePoint(ref plane, ref vertices[superTetrahedronVertex]) < 0.0f) + faceNormal = -faceNormal; // Sum normal to 3 vertices - outerVertexNormals[vertex0] += faceNormal; - outerVertexNormals[vertex1] += faceNormal; - outerVertexNormals[vertex2] += faceNormal; - } + outerVertexNormals[vertex0] += faceNormal; + outerVertexNormals[vertex1] += faceNormal; + outerVertexNormals[vertex2] += faceNormal; } } + // Normalize and generate extrapolated probe for (int i = 0; i < outerVertexNormals.Length; ++i) @@ -221,70 +219,74 @@ private unsafe void GenerateExtrapolationProbes() /// /// Generate faces info and normal. /// - private unsafe FastList GenerateFaces() + private unsafe List GenerateFaces() { - var faces = new FastList(); + var faces = new List(); var currentFace = new Face(); + var tetrahedralizationSpan = CollectionsMarshal.AsSpan(tetrahedralization); + var facesSpan = CollectionsMarshal.AsSpan(faces); - fixed (Tetrahedron* tetrahedra = tetrahedralization.Items) + for (int index = 0; index < tetrahedralizationSpan.Length; index++) { - for (int index = 0; index < tetrahedralization.Count; index++) - { - var currentTetrahedron = &tetrahedra[index]; + var currentTetrahedron = tetrahedralizationSpan[index]; - // Process each face - for (int i = 0; i < 4; ++i) - { - var neighbourTetrahedronIndex = currentTetrahedron->Neighbours[i]; + // Process each face + for (int i = 0; i < 4; ++i) + { + var neighbourTetrahedronIndex = currentTetrahedron.Neighbours[i]; - // If no neighbour, it means there is no face - if (neighbourTetrahedronIndex == -1) - continue; + // If no neighbour, it means there is no face + if (neighbourTetrahedronIndex == -1) + continue; - // Check if face is already created in neighbour tetrahedron - // If index is lower, it means it already exists (processed before) - if (neighbourTetrahedronIndex < index) + // Check if face is already created in neighbour tetrahedron + // If index is lower, it means it already exists (processed before) + if (neighbourTetrahedronIndex < index) + { + // Find which face are we in the neighbour tetrahedron + var neighbourTetrahedron = tetrahedralizationSpan[neighbourTetrahedronIndex]; + for (int j = 0; j < 4; ++j) { - // Find which face are we in the neighbour tetrahedron - var neighbourTetrahedron = &tetrahedra[neighbourTetrahedronIndex]; - for (int j = 0; j < 4; ++j) + if (neighbourTetrahedron.Neighbours[j] == index) { - if (neighbourTetrahedron->Neighbours[j] == index) - { - // We store the bitwise complement since normal is opposite - var oppositeFaceIndex = neighbourTetrahedron->Faces[j]; - currentTetrahedron->Faces[i] = ~oppositeFaceIndex; - faces.Items[oppositeFaceIndex].BackTetrahedron = index; - faces.Items[oppositeFaceIndex].BackFace = (sbyte)i; - break; - } + // We store the bitwise complement since normal is opposite + var oppositeFaceIndex = neighbourTetrahedron.Faces[j]; + + ref var currentTetrahedronRef = ref tetrahedralizationSpan[index]; + currentTetrahedronRef.Faces[i] = ~oppositeFaceIndex; + + ref var oppositeFaceRef = ref facesSpan[oppositeFaceIndex]; + oppositeFaceRef.BackTetrahedron = index; + oppositeFaceRef.BackFace = (sbyte)i; + break; } } - else - { - // New face, let's create it - currentTetrahedron->Faces[i] = faces.Count; - - // Create face - currentFace.FrontTetrahedron = index; - currentFace.FrontFace = (sbyte)i; - currentFace.BackTetrahedron = -1; - currentFace.BackFace = -1; - currentFace.Vertices[0] = currentTetrahedron->Vertices[(i + 1) % 4]; // 1 2 3 0 - currentFace.Vertices[1] = currentTetrahedron->Vertices[3 - (i / 2) * 2]; // 3 3 1 1 - currentFace.Vertices[2] = currentTetrahedron->Vertices[(((i + 3) / 2) * 2) % 4]; // 2 0 0 2 - - // Compute normal - Vector3 edge1, edge2, faceNormal; - Vector3.Subtract(ref vertices[currentFace.Vertices[1]], ref vertices[currentFace.Vertices[0]], out edge1); - Vector3.Subtract(ref vertices[currentFace.Vertices[2]], ref vertices[currentFace.Vertices[0]], out edge2); - Vector3.Cross(ref edge1, ref edge2, out faceNormal); - faceNormal.Normalize(); - - currentFace.Normal = faceNormal; - - faces.Add(currentFace); - } + } + else + { + // New face, let's create it + currentTetrahedron.Faces[i] = faces.Count; + + // Create face + currentFace.FrontTetrahedron = index; + currentFace.FrontFace = (sbyte)i; + currentFace.BackTetrahedron = -1; + currentFace.BackFace = -1; + currentFace.Vertices[0] = currentTetrahedron.Vertices[(i + 1) % 4]; // 1 2 3 0 + currentFace.Vertices[1] = currentTetrahedron.Vertices[3 - (i / 2) * 2]; // 3 3 1 1 + currentFace.Vertices[2] = currentTetrahedron.Vertices[(((i + 3) / 2) * 2) % 4]; // 2 0 0 2 + + // Compute normal + Vector3 edge1, edge2, faceNormal; + Vector3.Subtract(ref vertices[currentFace.Vertices[1]], ref vertices[currentFace.Vertices[0]], out edge1); + Vector3.Subtract(ref vertices[currentFace.Vertices[2]], ref vertices[currentFace.Vertices[0]], out edge2); + Vector3.Cross(ref edge1, ref edge2, out faceNormal); + faceNormal.Normalize(); + + currentFace.Normal = faceNormal; + + faces.Add(currentFace); + facesSpan = CollectionsMarshal.AsSpan(faces); } } } @@ -296,49 +298,51 @@ private unsafe FastList GenerateFaces() /// private unsafe void CleanupUnusedTetrahedra() { - fixed (Tetrahedron* tetrahedra = tetrahedralization.Items) + var tetrahedralizationSpan = CollectionsMarshal.AsSpan(tetrahedralization); + + for (int index = 0; index < tetrahedralizationSpan.Length; index++) { - for (int index = 0; index < tetrahedralization.Count; index++) + if (!IsTetrahedronAllocated(index, tetrahedralizationSpan)) { - if (!IsTetrahedronAllocated(index)) - { - // This is an unused tetrahedra, let's remove it - var currentTetrahedron = &tetrahedra[index]; + // This is an unused tetrahedra, let's remove it + ref var currentTetrahedron = ref tetrahedralizationSpan[index]; - // Swap-remove with latest tetrahedra (prevents RemoveAt shifting, only one tetrahedra is moving and needs its neighbour references updated) - int lastIndex = tetrahedralization.Count - 1; - if (index < lastIndex) + // Swap-remove with latest tetrahedra (prevents RemoveAt shifting, only one tetrahedra is moving and needs its neighbour references updated) + int lastIndex = tetrahedralization.Count - 1; + if (index < lastIndex) + { + if (IsTetrahedronAllocated(lastIndex, tetrahedralizationSpan)) { - if (IsTetrahedronAllocated(lastIndex)) + currentTetrahedron = tetrahedralizationSpan[lastIndex]; + + // We moved an allocated tretrahedra, we need to update neighbour indices pointing to this tetrahedra + // (neighbours pointing to lastIndex should now point to index) + for (int i = 0; i < 4; ++i) { - *currentTetrahedron = tetrahedra[lastIndex]; + var neighbourTetrahedronIndex = currentTetrahedron.Neighbours[i]; + if (neighbourTetrahedronIndex == -1) + continue; - // We moved an allocated tretrahedra, we need to update neighbour indices pointing to this tetrahedra - // (neighbours pointing to lastIndex should now point to index) - for (int i = 0; i < 4; ++i) + ref var neighbourTetrahedron = ref tetrahedralizationSpan[neighbourTetrahedronIndex]; + for (int j = 0; j < 4; ++j) { - var neighbourTetrahedronIndex = currentTetrahedron->Neighbours[i]; - if (neighbourTetrahedronIndex == -1) - continue; - - var neighbourTetrahedron = &tetrahedra[neighbourTetrahedronIndex]; - for (int j = 0; j < 4; ++j) - { - if (neighbourTetrahedron->Neighbours[j] == lastIndex) - neighbourTetrahedron->Neighbours[j] = index; - } + if (neighbourTetrahedron.Neighbours[j] == lastIndex) + neighbourTetrahedron.Neighbours[j] = index; } } - else - { - // Current tetrahedra is still not allocated. Go one step backward, so that next loop will also remove it. - index--; - } } - - tetrahedralization.RemoveAt(lastIndex); + else + { + // Current tetrahedra is still not allocated. Go one step backward, so that next loop will also remove it. + index--; + } } + + tetrahedralization.RemoveAt(lastIndex); + // Reduce length of the span by one given that we just removed an item from the list the span originates from + tetrahedralizationSpan = tetrahedralizationSpan[..^1]; } + // We can clear the free list as well freeTetrahedra.Clear(); @@ -350,41 +354,39 @@ private unsafe void CleanupUnusedTetrahedra() /// private unsafe void RemoveSuperTetrahedron(int startVertex, int endVertex) { - fixed (Tetrahedron* tetrahedra = tetrahedralization.Items) + var tetrahedralizationSpan = CollectionsMarshal.AsSpan(tetrahedralization); + for (int index = 0; index < tetrahedralizationSpan.Length; index++) { - for (int index = 0; index < tetrahedralization.Count; index++) - { - if (!IsTetrahedronAllocated(index)) - continue; + if (!IsTetrahedronAllocated(index, tetrahedralizationSpan)) + continue; - var tetrahedron = &tetrahedra[index]; + var tetrahedron = tetrahedralizationSpan[index]; - // Remove tetrahedra which have any point common with super tetrahedra (last 4 vertices) - for (int i = 0; i < 4; ++i) + // Remove tetrahedra which have any point common with super tetrahedra (last 4 vertices) + for (int i = 0; i < 4; ++i) + { + if (tetrahedron.Vertices[i] >= startVertex && tetrahedron.Vertices[i] < endVertex) { - if (tetrahedron->Vertices[i] >= startVertex && tetrahedron->Vertices[i] < endVertex) - { - FreeTetrahedron(index); - break; - } + FreeTetrahedron(index, tetrahedralizationSpan); + break; } } + } - // Remove invalid neighbour (pointing to nodes that were just deleted) - for (int index = 0; index < tetrahedralization.Count; index++) - { - if (!IsTetrahedronAllocated(index)) - continue; + // Remove invalid neighbour (pointing to nodes that were just deleted) + for (int index = 0; index < tetrahedralizationSpan.Length; index++) + { + if (!IsTetrahedronAllocated(index, tetrahedralizationSpan)) + continue; - var tetrahedron = &tetrahedra[index]; + ref var tetrahedron = ref tetrahedralizationSpan[index]; - // Remove tetrahedra which have any point common with super tetrahedra (last 4 vertices) - for (int i = 0; i < 4; ++i) - { - var neighbour = tetrahedron->Neighbours[i]; - if (neighbour != -1 && !IsTetrahedronAllocated(neighbour)) - tetrahedron->Neighbours[i] = -1; - } + // Remove tetrahedra which have any point common with super tetrahedra (last 4 vertices) + for (int i = 0; i < 4; ++i) + { + var neighbour = tetrahedron.Neighbours[i]; + if (neighbour != -1 && !IsTetrahedronAllocated(neighbour, tetrahedralizationSpan)) + tetrahedron.Neighbours[i] = -1; } } } @@ -446,96 +448,94 @@ private unsafe void AddVertex(int vertexIndex) edges.Clear(); var vertex = vertices[vertexIndex]; - - fixed (Tetrahedron* tetrahedra = tetrahedralization.Items) + var tetrahedralizationSpan = CollectionsMarshal.AsSpan(tetrahedralization); + + // First, find all the triangles that are no longer valid due to the insertion + // TODO: Currently O(N^2); "By using the connectivity of the triangulation to efficiently locate triangles to remove, the algorithm can take O(N log N)" + for (int index = 0; index < tetrahedralizationSpan.Length; index++) { - // First, find all the triangles that are no longer valid due to the insertion - // TODO: Currently O(N^2); "By using the connectivity of the triangulation to efficiently locate triangles to remove, the algorithm can take O(N log N)" - for (int index = 0; index < tetrahedralization.Count; index++) - { - if (IsTetrahedronAllocated(index) && IsPointInCircumsphere(ref vertex, vertices, ref tetrahedra[index])) - badTetrahedra.Add(index); - } + if (IsTetrahedronAllocated(index, tetrahedralizationSpan) && IsPointInCircumsphere(ref vertex, vertices, ref tetrahedralizationSpan[index])) + badTetrahedra.Add(index); + } - // Find the boundary of the polygonal hole - foreach (var tetrahedronIndex in badTetrahedra) + // Find the boundary of the polygonal hole + foreach (var tetrahedronIndex in badTetrahedra) + { + var tetrahedron = tetrahedralizationSpan[tetrahedronIndex]; + for (int i = 0; i < 4; ++i) { - var tetrahedron = &tetrahedra[tetrahedronIndex]; - for (int i = 0; i < 4; ++i) + // If edge is not shared by any other bad tetrahedra, it means it's a boundary of our polygonal hole + var neighbourTetrahedronIndex = tetrahedron.Neighbours[i]; + if (badTetrahedra.BinarySearch(neighbourTetrahedronIndex) < 0) { - // If edge is not shared by any other bad tetrahedra, it means it's a boundary of our polygonal hole - var neighbourTetrahedronIndex = tetrahedron->Neighbours[i]; - if (badTetrahedra.BinarySearch(neighbourTetrahedronIndex) < 0) + var neighbourTetrahedronSelfIndex = -1; + if (neighbourTetrahedronIndex != -1) { - var neighbourTetrahedronSelfIndex = -1; - if (neighbourTetrahedronIndex != -1) + // Find the neighbour index of current tetrahedra in neighbourTetrahedra + ref var neighbourTetrahedron = ref tetrahedralizationSpan[neighbourTetrahedronIndex]; + for (int j = 0; j < 4; ++j) { - // Find the neighbour index of current tetrahedra in neighbourTetrahedra - var neighbourTetrahedron = &tetrahedra[neighbourTetrahedronIndex]; - for (int j = 0; j < 4; ++j) + if (neighbourTetrahedron.Neighbours[j] == tetrahedronIndex) { - if (neighbourTetrahedron->Neighbours[j] == tetrahedronIndex) - { - neighbourTetrahedronSelfIndex = j; - break; - } + neighbourTetrahedronSelfIndex = j; + break; } - if (neighbourTetrahedronSelfIndex == -1) - throw new InvalidOperationException("Inconsistency: two tetrahedra don't agree on their neighbour information (they should both reference each other)"); } + if (neighbourTetrahedronSelfIndex == -1) + throw new InvalidOperationException("Inconsistency: two tetrahedra don't agree on their neighbour information (they should both reference each other)"); + } - // Store edges information (to easily reconstruct neighbour after) - var vertex0 = tetrahedron->Vertices[(i + 1) % 4]; - var vertex1 = tetrahedron->Vertices[(i + 2) % 4]; - var vertex2 = tetrahedron->Vertices[(i + 3) % 4]; + // Store edges information (to easily reconstruct neighbour after) + var vertex0 = tetrahedron.Vertices[(i + 1) % 4]; + var vertex1 = tetrahedron.Vertices[(i + 2) % 4]; + var vertex2 = tetrahedron.Vertices[(i + 3) % 4]; - // If new vertex is at an odd position, it means that newly constructed tetrahedron would have a negative order, let's swap 2 vertices - //if (!IsTetrahedraPositiveOrder(ref vertex, ref vertices[vertex0], ref vertices[vertex1], ref vertices[vertex2])) - if (i % 2 == 1) - { - var vertexTemp = vertex1; - vertex1 = vertex2; - vertex2 = vertexTemp; - } + // If new vertex is at an odd position, it means that newly constructed tetrahedron would have a negative order, let's swap 2 vertices + //if (!IsTetrahedraPositiveOrder(ref vertex, ref vertices[vertex0], ref vertices[vertex1], ref vertices[vertex2])) + if (i % 2 == 1) + { + var vertexTemp = vertex1; + vertex1 = vertex2; + vertex2 = vertexTemp; + } - if (!IsTetrahedronPositiveOrder(ref vertex, ref vertices[vertex0], ref vertices[vertex1], ref vertices[vertex2])) - throw new InvalidOperationException(); + if (!IsTetrahedronPositiveOrder(ref vertex, ref vertices[vertex0], ref vertices[vertex1], ref vertices[vertex2])) + throw new InvalidOperationException(); - holeFaces.Add(new HoleFace(vertex0, vertex1, vertex2, neighbourTetrahedronIndex, neighbourTetrahedronSelfIndex)); - } + holeFaces.Add(new HoleFace(vertex0, vertex1, vertex2, neighbourTetrahedronIndex, neighbourTetrahedronSelfIndex)); } } + } - // Remove bad tetrahedra (by marking them invalid) - foreach (var tetrahedronIndex in badTetrahedra) - { - FreeTetrahedron(tetrahedronIndex); - } + // Remove bad tetrahedra (by marking them invalid) + foreach (var tetrahedronIndex in badTetrahedra) + { + FreeTetrahedron(tetrahedronIndex, tetrahedralizationSpan); } + var holeFacesSpan = CollectionsMarshal.AsSpan(holeFaces); // Allocate tetrahedron, and build edge list - fixed (HoleFace* facesPointer = holeFaces.Items) + for (int index = 0; index < holeFaces.Count; index++) { - for (int index = 0; index < holeFaces.Count; index++) - { - var face = &facesPointer[index]; + ref var face = ref holeFacesSpan[index]; - var tetrahedronIndex = AllocateTetrahedron(); - face->Tetrahedron = tetrahedronIndex; + var tetrahedronIndex = AllocateTetrahedron(); + face.Tetrahedron = tetrahedronIndex; - if (!IsTetrahedronPositiveOrder(ref vertex, ref vertices[face->Vertex0], ref vertices[face->Vertex1], ref vertices[face->Vertex2])) - throw new InvalidOperationException(); + if (!IsTetrahedronPositiveOrder(ref vertex, ref vertices[face.Vertex0], ref vertices[face.Vertex1], ref vertices[face.Vertex2])) + throw new InvalidOperationException(); - // Note: we use opposite direction for half-edge - edges.Add(new HoleEdge(face->Vertex0, face->Vertex1, tetrahedronIndex)); - edges.Add(new HoleEdge(face->Vertex1, face->Vertex2, tetrahedronIndex)); - edges.Add(new HoleEdge(face->Vertex2, face->Vertex0, tetrahedronIndex)); - } + // Note: we use opposite direction for half-edge + edges.Add(new HoleEdge(face.Vertex0, face.Vertex1, tetrahedronIndex)); + edges.Add(new HoleEdge(face.Vertex1, face.Vertex2, tetrahedronIndex)); + edges.Add(new HoleEdge(face.Vertex2, face.Vertex0, tetrahedronIndex)); } // Sort hole edges to be able to binary search them when reconstructing neighbour information edges.Sort(); + tetrahedralizationSpan = CollectionsMarshal.AsSpan(tetrahedralization); // Fetch latest state of the list as a span + // Re-triangulate the polygonal hole foreach (var face in holeFaces) { @@ -543,75 +543,70 @@ private unsafe void AddVertex(int vertexIndex) // This should be outside of "fixed" statement since triangulation list might grow var tetrahedronIndex = face.Tetrahedron; - fixed (Tetrahedron* tetrahedra = tetrahedralization.Items) - { - var newTetrahedron = &tetrahedra[tetrahedronIndex]; + ref var newTetrahedron = ref tetrahedralizationSpan[tetrahedronIndex]; - if (face.Neighbour != -1) - { - // Update neighbour reference to self - var neighbourTetrahedron = &tetrahedra[face.Neighbour]; - neighbourTetrahedron->Neighbours[face.NeighbourFaceIndex] = tetrahedronIndex; - } + if (face.Neighbour != -1) + { + // Update neighbour reference to self + ref var neighbourTetrahedron = ref tetrahedralizationSpan[face.Neighbour]; + neighbourTetrahedron.Neighbours[face.NeighbourFaceIndex] = tetrahedronIndex; + } - newTetrahedron->Vertices[0] = vertexIndex; + newTetrahedron.Vertices[0] = vertexIndex; - var tetrahedronAdjacentIndex0 = edges.BinarySearch(new HoleEdge(face.Vertex2, face.Vertex1)); - var tetrahedronAdjacentIndex1 = edges.BinarySearch(new HoleEdge(face.Vertex0, face.Vertex2)); - var tetrahedronAdjacentIndex2 = edges.BinarySearch(new HoleEdge(face.Vertex1, face.Vertex0)); + var tetrahedronAdjacentIndex0 = edges.BinarySearch(new HoleEdge(face.Vertex2, face.Vertex1)); + var tetrahedronAdjacentIndex1 = edges.BinarySearch(new HoleEdge(face.Vertex0, face.Vertex2)); + var tetrahedronAdjacentIndex2 = edges.BinarySearch(new HoleEdge(face.Vertex1, face.Vertex0)); - //if (tetrahedraAdjacentIndex0 < 0 || tetrahedraAdjacentIndex1 < 0 || tetrahedraAdjacentIndex2 < 0) - // throw new InvalidOperationException("Could not find adjacent tetrahedra."); + //if (tetrahedraAdjacentIndex0 < 0 || tetrahedraAdjacentIndex1 < 0 || tetrahedraAdjacentIndex2 < 0) + // throw new InvalidOperationException("Could not find adjacent tetrahedra."); - // Add the shared face, in opposite order (so that tetrahedron is still positive order) - newTetrahedron->Vertices[1] = face.Vertex0; - newTetrahedron->Vertices[2] = face.Vertex1; - newTetrahedron->Vertices[3] = face.Vertex2; + // Add the shared face, in opposite order (so that tetrahedron is still positive order) + newTetrahedron.Vertices[1] = face.Vertex0; + newTetrahedron.Vertices[2] = face.Vertex1; + newTetrahedron.Vertices[3] = face.Vertex2; - // Neighbour at boundary is always opposite of newly added vertex - newTetrahedron->Neighbours[0] = face.Neighbour; + // Neighbour at boundary is always opposite of newly added vertex + newTetrahedron.Neighbours[0] = face.Neighbour; - newTetrahedron->Neighbours[1] = tetrahedronAdjacentIndex0 >= 0 ? edges[tetrahedronAdjacentIndex0].Neighboor : -1; - newTetrahedron->Neighbours[2] = tetrahedronAdjacentIndex1 >= 0 ? edges[tetrahedronAdjacentIndex1].Neighboor : -1; - newTetrahedron->Neighbours[3] = tetrahedronAdjacentIndex2 >= 0 ? edges[tetrahedronAdjacentIndex2].Neighboor : -1; + newTetrahedron.Neighbours[1] = tetrahedronAdjacentIndex0 >= 0 ? edges[tetrahedronAdjacentIndex0].Neighboor : -1; + newTetrahedron.Neighbours[2] = tetrahedronAdjacentIndex1 >= 0 ? edges[tetrahedronAdjacentIndex1].Neighboor : -1; + newTetrahedron.Neighbours[3] = tetrahedronAdjacentIndex2 >= 0 ? edges[tetrahedronAdjacentIndex2].Neighboor : -1; - if (!IsTetrahedronPositiveOrder(vertices, ref *newTetrahedron)) - throw new InvalidOperationException("Tetrahedron not in positive order"); - } + if (!IsTetrahedronPositiveOrder(vertices, ref newTetrahedron)) + throw new InvalidOperationException("Tetrahedron not in positive order"); } } private unsafe void CheckConnectivity() { + var tetrahedralizationSpan = CollectionsMarshal.AsSpan(tetrahedralization); // Check connectivity - fixed (Tetrahedron* tetrahedra = tetrahedralization.Items) + for (int index = 0; index < tetrahedralizationSpan.Length; index++) { - for (int index = 0; index < tetrahedralization.Count; index++) - { - if (!IsTetrahedronAllocated(index)) - continue; + if (!IsTetrahedronAllocated(index, tetrahedralizationSpan)) + continue; - var tetrahedron = &tetrahedra[index]; + ref var tetrahedron = ref tetrahedralizationSpan[index]; - for (int i = 0; i < 4; ++i) + for (int i = 0; i < 4; ++i) + { + var neighbourTetrahedronIndex = tetrahedron.Neighbours[i]; + var neighbourTetrahedronSelfIndex = -1; + if (neighbourTetrahedronIndex != -1) { - var neighbourTetrahedronIndex = tetrahedron->Neighbours[i]; - var neighbourTetrahedronSelfIndex = -1; - if (neighbourTetrahedronIndex != -1) + // Find the neighbour index of current tetrahedron in neighbourTetrahedron + ref var neighbourTetrahedron = ref tetrahedralizationSpan[neighbourTetrahedronIndex]; + for (int j = 0; j < 4; ++j) { - // Find the neighbour index of current tetrahedron in neighbourTetrahedron - var neighbourTetrahedron = &tetrahedra[neighbourTetrahedronIndex]; - for (int j = 0; j < 4; ++j) + if (neighbourTetrahedron.Neighbours[j] == index) { - if (neighbourTetrahedron->Neighbours[j] == index) - { - neighbourTetrahedronSelfIndex = j; - break; - } + neighbourTetrahedronSelfIndex = j; + break; } - if (neighbourTetrahedronSelfIndex == -1) - throw new InvalidOperationException("Inconsistency: two tetrahedra don't agree on their neighbour information (they should both reference each other)"); } + if (neighbourTetrahedronSelfIndex == -1) + throw new InvalidOperationException("Inconsistency: two tetrahedra don't agree on their neighbour information (they should both reference each other)"); } } } @@ -633,24 +628,18 @@ private int AllocateTetrahedron() return tetrahedralization.Count - 1; } - private unsafe bool IsTetrahedronAllocated(int index) + private static unsafe bool IsTetrahedronAllocated(int index, Span tetrahedronSpan) { - fixed (Tetrahedron* tetrahedron = &tetrahedralization.Items[index]) - { - return tetrahedron->Vertices[0] != -1; - } + return tetrahedronSpan[index].Vertices[0] != -1; } - private unsafe void FreeTetrahedron(int index) + private unsafe void FreeTetrahedron(int index, Span tetrahedronSpan) { // Mark it as "unused" - fixed (Tetrahedron* tetrahedron = &tetrahedralization.Items[index]) - { - tetrahedron->Vertices[0] = -1; + tetrahedronSpan[index].Vertices[0] = -1; - // Add it to free list - freeTetrahedra.Add(index); - } + // Add it to free list + freeTetrahedra.Add(index); } /// diff --git a/sources/engine/Stride.Rendering/Rendering/LightProbes/LightProbeRenderer.cs b/sources/engine/Stride.Rendering/Rendering/LightProbes/LightProbeRenderer.cs index 42fe407750..c68469d598 100644 --- a/sources/engine/Stride.Rendering/Rendering/LightProbes/LightProbeRenderer.cs +++ b/sources/engine/Stride.Rendering/Rendering/LightProbes/LightProbeRenderer.cs @@ -46,7 +46,7 @@ public override void Reset() lightprobeGroup.Reset(); } - public override void SetViews(FastList views) + public override void SetViews(List views) { base.SetViews(views); diff --git a/sources/engine/Stride.Rendering/Rendering/LightProbes/LightProbeRuntimeData.cs b/sources/engine/Stride.Rendering/Rendering/LightProbes/LightProbeRuntimeData.cs index c434de344d..c50c4a142b 100644 --- a/sources/engine/Stride.Rendering/Rendering/LightProbes/LightProbeRuntimeData.cs +++ b/sources/engine/Stride.Rendering/Rendering/LightProbes/LightProbeRuntimeData.cs @@ -31,8 +31,8 @@ public class LightProbeRuntimeData // Computed data public Vector3[] Vertices; public int UserVertexCount; - public FastList Tetrahedra; - public FastList Faces; + public List Tetrahedra; + public List Faces; // Data to upload to GPU public Color3[] Coefficients; diff --git a/sources/engine/Stride.Rendering/Rendering/Lights/ForwardLightingRenderFeature.cs b/sources/engine/Stride.Rendering/Rendering/Lights/ForwardLightingRenderFeature.cs index b4f876a04b..a32374447e 100644 --- a/sources/engine/Stride.Rendering/Rendering/Lights/ForwardLightingRenderFeature.cs +++ b/sources/engine/Stride.Rendering/Rendering/Lights/ForwardLightingRenderFeature.cs @@ -80,7 +80,7 @@ public RenderViewLightData() // Preallocted for CollectVisibleLights private readonly HashSet processedRenderViews = new HashSet(); - private readonly FastList renderViews = new FastList(); + private readonly List renderViews = []; private readonly Dictionary shaderSourcesReadonlyCache = new Dictionary(); @@ -613,7 +613,7 @@ private void CollectVisibleLights() processedRenderViews.Clear(); } - private void PrepareLightGroups(RenderDrawContext context, FastList renderViews, RenderView renderView, RenderViewLightData renderViewData, IShadowMapRenderer shadowMapRenderer, RenderGroup group) + private void PrepareLightGroups(RenderDrawContext context, List renderViews, RenderView renderView, RenderViewLightData renderViewData, IShadowMapRenderer shadowMapRenderer, RenderGroup group) { var viewIndex = renderViews.IndexOf(renderView); @@ -723,17 +723,6 @@ private void EvaluateLightTypes() public class LightShaderPermutationEntry { - public LightShaderPermutationEntry() - { - DirectLightGroups = new FastListStruct(8); - EnvironmentLights = new FastListStruct(8); - - PermutationLightGroups = new FastListStruct(2); - - DirectLightShaders = new ShaderSourceCollection(); - EnvironmentLightShaders = new ShaderSourceCollection(); - } - public void Reset() { DirectLightGroups.Clear(); @@ -745,18 +734,18 @@ public void Reset() PermutationLightGroups.Clear(); } - public FastListStruct DirectLightGroups; + public FastListStruct DirectLightGroups = new(8); - public readonly ShaderSourceCollection DirectLightShaders; + public readonly ShaderSourceCollection DirectLightShaders = new(); - public FastListStruct EnvironmentLights; + public FastListStruct EnvironmentLights = new(8); - public readonly ShaderSourceCollection EnvironmentLightShaders; + public readonly ShaderSourceCollection EnvironmentLightShaders = new(); /// /// Light groups that have . /// - public FastListStruct PermutationLightGroups; + public FastListStruct PermutationLightGroups = new(2); } internal struct ActiveLightGroupRenderer diff --git a/sources/engine/Stride.Rendering/Rendering/Lights/LightAmbientRenderer.cs b/sources/engine/Stride.Rendering/Rendering/Lights/LightAmbientRenderer.cs index ff76946d9d..1bd1223b7e 100644 --- a/sources/engine/Stride.Rendering/Rendering/Lights/LightAmbientRenderer.cs +++ b/sources/engine/Stride.Rendering/Rendering/Lights/LightAmbientRenderer.cs @@ -2,6 +2,7 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; +using System.Collections.Generic; using Stride.Core.Collections; using Stride.Core.Mathematics; using Stride.Engine; @@ -31,7 +32,7 @@ public override void Reset() lightShaderGroup.Reset(); } - public override void SetViews(FastList views) + public override void SetViews(List views) { base.SetViews(views); diff --git a/sources/engine/Stride.Rendering/Rendering/Lights/LightClusteredPointSpotGroupRenderer.cs b/sources/engine/Stride.Rendering/Rendering/Lights/LightClusteredPointSpotGroupRenderer.cs index 3d515fdd1a..436b307520 100644 --- a/sources/engine/Stride.Rendering/Rendering/Lights/LightClusteredPointSpotGroupRenderer.cs +++ b/sources/engine/Stride.Rendering/Rendering/Lights/LightClusteredPointSpotGroupRenderer.cs @@ -68,7 +68,7 @@ public override void Reset() spotGroup.Reset(); } - public override void SetViews(FastList views) + public override void SetViews(List views) { base.SetViews(views); @@ -202,7 +202,7 @@ public override void Reset() } /// - public override void SetViews(FastList views) + public override void SetViews(List views) { base.SetViews(views); diff --git a/sources/engine/Stride.Rendering/Rendering/Lights/LightGroupRendererBase.cs b/sources/engine/Stride.Rendering/Rendering/Lights/LightGroupRendererBase.cs index afea14392c..cbe58386cf 100644 --- a/sources/engine/Stride.Rendering/Rendering/Lights/LightGroupRendererBase.cs +++ b/sources/engine/Stride.Rendering/Rendering/Lights/LightGroupRendererBase.cs @@ -51,7 +51,7 @@ public virtual void Reset() { } - public virtual void SetViews(FastList views) + public virtual void SetViews(List views) { } @@ -64,7 +64,7 @@ public struct ProcessLightsParameters // Information about the view public int ViewIndex; public RenderView View; - public FastList Views; + public List Views; // Current renderers in this group public LightGroupRendererBase[] Renderers; diff --git a/sources/engine/Stride.Rendering/Rendering/Lights/LightGroupRendererShadow.cs b/sources/engine/Stride.Rendering/Rendering/Lights/LightGroupRendererShadow.cs index e5a5dd1669..0135139b55 100644 --- a/sources/engine/Stride.Rendering/Rendering/Lights/LightGroupRendererShadow.cs +++ b/sources/engine/Stride.Rendering/Rendering/Lights/LightGroupRendererShadow.cs @@ -69,8 +69,8 @@ public override int GetHashCode() public abstract class LightGroupRendererShadow : LightGroupRendererDynamic { private readonly ShadowComparer shadowComparer = new ShadowComparer(); - private readonly Dictionary lightShaderGroupPool = new Dictionary(); - private readonly FastList> lightShaderGroups = new FastList>(); + private readonly Dictionary lightShaderGroupPool = []; + private readonly List> lightShaderGroups = []; private FastListStruct processedLights = new FastListStruct(8); public override Type[] LightTypes { get; } @@ -87,7 +87,7 @@ public override void Reset() } } - public override void SetViews(FastList views) + public override void SetViews(List views) { base.SetViews(views); diff --git a/sources/engine/Stride.Rendering/Rendering/Lights/LightShaderGroupDynamic.cs b/sources/engine/Stride.Rendering/Rendering/Lights/LightShaderGroupDynamic.cs index f3495a2341..4705270ca2 100644 --- a/sources/engine/Stride.Rendering/Rendering/Lights/LightShaderGroupDynamic.cs +++ b/sources/engine/Stride.Rendering/Rendering/Lights/LightShaderGroupDynamic.cs @@ -1,9 +1,9 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; +using System.Collections.Generic; using Stride.Core.Collections; using Stride.Core.Mathematics; -using Stride.Engine; using Stride.Graphics; using Stride.Rendering.Shadows; @@ -49,7 +49,7 @@ public override void Reset() LightCurrentCount = 0; } - public virtual void SetViews(FastList views) + public virtual void SetViews(List views) { Array.Resize(ref lightRanges, views.Count); diff --git a/sources/engine/Stride.Rendering/Rendering/Lights/LightSpotGroupRenderer.cs b/sources/engine/Stride.Rendering/Rendering/Lights/LightSpotGroupRenderer.cs index e4f6ec582e..24be24d507 100644 --- a/sources/engine/Stride.Rendering/Rendering/Lights/LightSpotGroupRenderer.cs +++ b/sources/engine/Stride.Rendering/Rendering/Lights/LightSpotGroupRenderer.cs @@ -19,7 +19,7 @@ public class LightSpotGroupRenderer : LightGroupRendererDynamic { private readonly ShadowComparer shadowComparer = new ShadowComparer(); private FastListStruct processedLights = new FastListStruct(8); - private readonly FastList> lightShaderGroups = new FastList>(); + private readonly List> lightShaderGroups = []; private readonly Dictionary textureProjectionRenderers = new Dictionary(); private readonly Dictionary lightShaderGroupPool = new Dictionary(); @@ -64,7 +64,7 @@ public override void Reset() } } - public override void SetViews(FastList views) + public override void SetViews(List views) { base.SetViews(views); diff --git a/sources/engine/Stride.Rendering/Rendering/Lights/RenderLightCollection.cs b/sources/engine/Stride.Rendering/Rendering/Lights/RenderLightCollection.cs index ed817484de..2d40b6d38f 100644 --- a/sources/engine/Stride.Rendering/Rendering/Lights/RenderLightCollection.cs +++ b/sources/engine/Stride.Rendering/Rendering/Lights/RenderLightCollection.cs @@ -1,16 +1,15 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +using System.Collections.Generic; using Stride.Core; -using Stride.Core.Collections; -using Stride.Engine; namespace Stride.Rendering.Lights { /// /// A list of for a specified . /// - public class RenderLightCollection : FastList + public class RenderLightCollection : List { /// /// Initializes a new instance of the class. diff --git a/sources/engine/Stride.Rendering/Rendering/RenderSystem.cs b/sources/engine/Stride.Rendering/Rendering/RenderSystem.cs index 6adda25f30..7b246dc26f 100644 --- a/sources/engine/Stride.Rendering/Rendering/RenderSystem.cs +++ b/sources/engine/Stride.Rendering/Rendering/RenderSystem.cs @@ -22,7 +22,7 @@ public class RenderSystem : ComponentBase private readonly ConcurrentPool prepareThreadLocals = new ConcurrentPool(() => new PrepareThreadLocals()); private readonly ConcurrentPool> renderNodePool = new ConcurrentPool>(() => new ConcurrentCollector()); - private readonly ConcurrentPool> sortedRenderNodePool = new ConcurrentPool>(() => new FastList()); + private readonly ConcurrentPool> sortedRenderNodePool = new ConcurrentPool>(() => []); private CompiledCommandList[] commandLists; private Texture[] renderTargets; @@ -285,8 +285,16 @@ public unsafe void Prepare(RenderDrawContext context) var renderStage = RenderStages[renderViewStage.Index]; var sortedRenderNodes = renderViewStage.SortedRenderNodes; - // Fast clear, since it's cleared properly in Reset() - sortedRenderNodes.Resize(renderViewStage.RenderNodes.Count, true); + if (sortedRenderNodes.Count < renderNodes.Count) + { + sortedRenderNodes.EnsureCapacity(renderNodes.Count); + while (sortedRenderNodes.Count != renderNodes.Count) + sortedRenderNodes.Add(default); + } + else if (sortedRenderNodes.Count > renderNodes.Count) + { + sortedRenderNodes.RemoveRange(renderNodes.Count, sortedRenderNodes.Count - renderNodes.Count); + } if (renderStage.SortMode != null) { @@ -525,7 +533,7 @@ public void Reset() { // Slow clear, since type contains references renderViewStage.RenderNodes?.Clear(false); - renderViewStage.SortedRenderNodes?.Clear(false); + renderViewStage.SortedRenderNodes?.Clear(); if (renderViewStage.RenderNodes != null) renderNodePool.Release(renderViewStage.RenderNodes); if (renderViewStage.SortedRenderNodes != null) sortedRenderNodePool.Release(renderViewStage.SortedRenderNodes); diff --git a/sources/engine/Stride.Rendering/Rendering/RenderViewStage.cs b/sources/engine/Stride.Rendering/Rendering/RenderViewStage.cs index 49096704b3..cb57248665 100644 --- a/sources/engine/Stride.Rendering/Rendering/RenderViewStage.cs +++ b/sources/engine/Stride.Rendering/Rendering/RenderViewStage.cs @@ -42,7 +42,7 @@ public RenderViewStage(RenderStage renderStage) /// /// Sorted list of render nodes, that should be used during actual drawing. /// - public FastList SortedRenderNodes; + public List SortedRenderNodes; public static implicit operator RenderViewStage(RenderStage renderStage) { diff --git a/sources/engine/Stride.Shaders/EffectReflection.cs b/sources/engine/Stride.Shaders/EffectReflection.cs index 030d7f598d..afb3dcbedd 100644 --- a/sources/engine/Stride.Shaders/EffectReflection.cs +++ b/sources/engine/Stride.Shaders/EffectReflection.cs @@ -19,11 +19,11 @@ public class EffectReflection /// public EffectReflection() { - SamplerStates = new List(); - ResourceBindings = new FastList(); - ConstantBuffers = new List(); - ShaderStreamOutputDeclarations = new List(); - InputAttributes = new FastList(); + SamplerStates = []; + ResourceBindings = []; + ConstantBuffers = []; + ShaderStreamOutputDeclarations = []; + InputAttributes = []; } /// @@ -36,7 +36,7 @@ public EffectReflection() /// Gets the parameter binding descriptions. /// /// The resource bindings. - public FastList ResourceBindings { get; set; } + public List ResourceBindings { get; set; } /// /// Gets the constant buffer descriptions (if any). @@ -62,6 +62,6 @@ public EffectReflection() /// The stream output rasterized stream. public int StreamOutputRasterizedStream { get; set; } - public FastList InputAttributes { get; set; } + public List InputAttributes { get; set; } } } diff --git a/sources/engine/Stride/Rendering/ParameterCollection.cs b/sources/engine/Stride/Rendering/ParameterCollection.cs index 5e7654b7e0..fa8c7cf7dd 100644 --- a/sources/engine/Stride/Rendering/ParameterCollection.cs +++ b/sources/engine/Stride/Rendering/ParameterCollection.cs @@ -17,7 +17,7 @@ namespace Stride.Rendering /// Manage several effect parameters (resources and data). A specific data and resource layout can be forced (usually by the consuming effect). /// [DataSerializer(typeof(ParameterCollection.Serializer))] - [DataSerializerGlobal(null, typeof(FastList))] + [DataSerializerGlobal(null, typeof(List))] [DebuggerTypeProxy(typeof(ParameterCollection.DebugView))] public class ParameterCollection { @@ -28,11 +28,11 @@ public class ParameterCollection private ParameterCollectionLayout layout; // TODO: Switch to FastListStruct (for serialization) - private FastList parameterKeyInfos = new(4); + private List parameterKeyInfos = new(4); // Constants and resources [DataMemberIgnore] - public byte[] DataValues = Array.Empty(); + public byte[] DataValues = []; [DataMemberIgnore] public object[] ObjectValues; @@ -43,7 +43,7 @@ public class ParameterCollection public int LayoutCounter = 1; [DataMemberIgnore] - public FastList ParameterKeyInfos => parameterKeyInfos; + public List ParameterKeyInfos => parameterKeyInfos; [DataMemberIgnore] public ParameterCollectionLayout Layout => layout; @@ -78,7 +78,7 @@ public unsafe ParameterCollection(ParameterCollection parameterCollection) if (parameterCollection.DataValues != null) { if (parameterCollection.DataValues.Length == 0) - DataValues = Array.Empty(); + DataValues = []; else { DataValues = new byte[parameterCollection.DataValues.Length]; fixed (byte* dataValuesSources = parameterCollection.DataValues) @@ -155,12 +155,14 @@ public ValueParameter GetAccessor(ValueParameterKey parameterKey, int e private unsafe Accessor GetValueAccessorHelper(ParameterKey parameterKey, int elementCount = 1) { + var parameterKeyInfosSpan = CollectionsMarshal.AsSpan(parameterKeyInfos); + // Find existing first - for (int i = 0; i < parameterKeyInfos.Count; ++i) + for (int i = 0; i < parameterKeyInfosSpan.Length; ++i) { - if (parameterKeyInfos.Items[i].Key == parameterKey) + if (parameterKeyInfosSpan[i].Key == parameterKey) { - return parameterKeyInfos.Items[i].GetValueAccessor(); + return parameterKeyInfosSpan[i].GetValueAccessor(); } } @@ -557,8 +559,9 @@ public unsafe void UpdateLayout(ParameterCollectionLayout collectionLayout) var layoutParameterKeyInfos = collectionLayout.LayoutParameterKeyInfos; // Do a first pass to measure constant buffer size - var newParameterKeyInfos = new FastList(Math.Max(1, parameterKeyInfos.Count)); + var newParameterKeyInfos = new List(Math.Max(1, parameterKeyInfos.Count)); newParameterKeyInfos.AddRange(parameterKeyInfos); + var newParameterKeyInfosSpan = CollectionsMarshal.AsSpan(newParameterKeyInfos); var processedParameters = new bool[parameterKeyInfos.Count]; var bufferSize = collectionLayout.BufferSize; @@ -573,7 +576,7 @@ public unsafe void UpdateLayout(ParameterCollectionLayout collectionLayout) if (parameterKeyInfos[i].Key == layoutParameterKeyInfo.Key) { processedParameters[i] = true; - newParameterKeyInfos.Items[i] = layoutParameterKeyInfo; + newParameterKeyInfosSpan[i] = layoutParameterKeyInfo; break; } } @@ -591,17 +594,17 @@ public unsafe void UpdateLayout(ParameterCollectionLayout collectionLayout) if (parameterKeyInfo.Offset != -1) { // It's data - newParameterKeyInfos.Items[i].Offset = bufferSize; + newParameterKeyInfosSpan[i].Offset = bufferSize; var additionalSize = ComputeAlignedSizeMinusTrailingPadding( - elementSize: newParameterKeyInfos.Items[i].Key.Size, - newParameterKeyInfos.Items[i].Count); + elementSize: newParameterKeyInfosSpan[i].Key.Size, + newParameterKeyInfosSpan[i].Count); bufferSize += additionalSize; } else if (parameterKeyInfo.BindingSlot != -1) { // It's a resource - newParameterKeyInfos.Items[i].BindingSlot = resourceCount++; + newParameterKeyInfosSpan[i].BindingSlot = resourceCount++; } } @@ -686,12 +689,13 @@ public unsafe void UpdateLayout(ParameterCollectionLayout collectionLayout) protected Accessor GetObjectParameterHelper(ParameterKey parameterKey, bool createIfNew = true) { + var parameterKeyInfosSpan = CollectionsMarshal.AsSpan(parameterKeyInfos); // Find existing first - for (int i = 0; i < parameterKeyInfos.Count; ++i) + for (int i = 0; i < parameterKeyInfosSpan.Length; ++i) { - if (parameterKeyInfos.Items[i].Key == parameterKey) + if (parameterKeyInfosSpan[i].Key == parameterKey) { - return parameterKeyInfos.Items[i].GetObjectAccessor(); + return parameterKeyInfosSpan[i].GetObjectAccessor(); } }