-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
refactor: Discard internal use of FastList #2798
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Discard internal use of FastList #2798
Conversation
|
If this change is approved, I will replace all the fastlists as much as possible :) |
|
Small note, the idea would be to replace all codepaths referencing the internal array directly with the CollectionsMarshal.AsSpan(List) to avoid performance degradation. for (int i = 0; i < keyFrames.Count; ++i)
{
if (parentNodeIndex == 0)
keyFrames.Items[i].Value -= PivotPosition;
keyFrames.Items[i].Value *= ScaleImport;
}You would do var span = CollectionsMarshal.AsSpan(keyFrames);
for (int i = 0; i < span.Count; ++i)
{
if (parentNodeIndex == 0)
span[i].Value -= PivotPosition;
span[i].Value *= ScaleImport;
} |
thanks , i see ,i will change |
This reverts commit 7d72ba4.
|
|
||
| public class AnimationCurveEvaluatorDirectFloatGroup : AnimationCurveEvaluatorDirectBlittableGroupBase<float> | ||
| { | ||
| protected unsafe override void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, I Adjusted the location with unsafe and unsafe
sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs
Outdated
Show resolved
Hide resolved
sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectFloatGroup.cs
Outdated
Show resolved
Hide resolved
sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectFloatGroup.cs
Outdated
Show resolved
Hide resolved
sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectQuaternionGroup.cs
Outdated
Show resolved
Hide resolved
sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector3Group.cs
Outdated
Show resolved
Hide resolved
sources/engine/Stride.Engine/Animations/AnimationCurveEvaluatorDirectVector4Group.cs
Outdated
Show resolved
Hide resolved
| Sort(collection.Items, 0, collection.Count, comparer); | ||
| } | ||
|
|
||
| public static void Sort<T>(FastList<T> collection, IComparer<T> comparer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I delete this, because the method is 0 used , and if deleted , the scripts will easier to maintain , if not it will cause misunderstandings to others
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dispatcher is public, users could be calling this method in their project, so we should leave it for for now and remove it once we remove FastList<T>
| currentRenderTargetsNonMSAA.Clear(); | ||
| currentRenderTargetsNonMSAA.Capacity = currentRenderTargets.Count; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think:
.Resize =.Clear() + set Capacity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, this case isn't equivalent. In FastList<T> if the new capacity was smaller than the previous one, only its size was modified (i.e. no allocations). In List<T> in all cases (except when it's already the correct size) a new array is allocated and a copy occurs.
This will have impact on performance and was one of the reason FastList<T> was created.
Compare
stride/sources/core/Stride.Core/Collections/FastList.cs
Lines 220 to 232 in b2c29fd
| public void Resize(int newSize, bool fastClear) | |
| { | |
| if (size < newSize) | |
| { | |
| EnsureCapacity(newSize); | |
| } | |
| else if (!fastClear && size > newSize) | |
| { | |
| Array.Clear(Items, newSize, size - newSize); | |
| } | |
| size = newSize; | |
| } |
with
https://github.com/dotnet/runtime/blob/2765f1856d7ebcc0ebd9708e7a2322f565a1fc77/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs#L97-L124
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
List<T>.EnsureCapacity might be better.
|
I should have time to review this next week end if Kryptos doesn't do it by then |
Yes , thanks, I maybe try it , the key question is use more modern and better ways to improve performance, rather than just delete code :) 👍 |
|
👀 |
Eideren
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about the wait, pretty good work overall, just a few things to fix and some improvements you could tackle.
| var keyFrames = ((AnimationCurve<Vector3>)curve).KeyFrames; | ||
| var keyFramesSpan = CollectionsMarshal.AsSpan(keyFrames); | ||
| for (int i = 0; i < keyFrames.Count; ++i) | ||
| { | ||
| if (parentNodeIndex == 0) | ||
| keyFrames.Items[i].Value -= PivotPosition; | ||
| keyFrames.Items[i].Value *= ScaleImport; | ||
| keyFramesSpan[i].Value -= PivotPosition; | ||
| keyFramesSpan[i].Value *= ScaleImport; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keyFrames.Count -> keyFramesSpan.Length, using the span's length instead of the list's will allow dotnet to elide the bounds check, see https://sharplab.io/#v2:C4LghgzgtgPgAgJgIwFgBQcAMACOSAsA3OlrkgHQBKArgHbACWUApuQJL3MBOA9gA4BlbgDcGAY2YRiaEgGZcCbAGF0Ab3TZNueQ3rYAsgAoAMgwjAAPADMANjzDAAfNhsAabLfvAPASg1b1NC1g7GEwLmwIPjBabABeZR4bG2YxRh5aCH1wiAALMBtyAEEIAWjaQxsfaX8Qjx4Iw11vBnjsTEJsVosXciUeOmBOgGphhj8guuxAqZCGK2xDKJiAbQYAXXiEqwnZ4Jm9urgAdi7pQ80AX1qQ68m6m+CT7ABaJHOtO5u4HT19BBMZksngczjcHjsDl8NwOdTCEWWsQS/WSqXSmWyXDyBWKpXKlWq6EeWisDUWzS6bQ6lJ6iPIxmYtAA5sBciMxrsprC9vNFoi1ps4ttOYduRdcKcGB9DndZrKpsTNM83tLsHdLkA=
| currentRenderTargetsNonMSAA.Resize(currentRenderTargets.Count, false); | ||
| currentRenderTargetsNonMSAA.Clear(); | ||
| currentRenderTargetsNonMSAA.EnsureCapacity(currentRenderTargets.Count); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't quite the same, right now, the way you have it setup is that you're clearing the whole list and then making sure the list can contain at least currentRenderTargets.Count long.
Resize changes the list's capacity to hold the given amount, but also the list's length, so if it is 5 items long and you pass it 3, it will be 3 items long from then on, but it's capacity will still be 5 or whichever capacity the list had at the time.
And passing false to Resize only affects the list when decreasing its length, so when the list is 5 items in length and is changed to 3 items in length, the 4th and 5th item will be set to null/default.
| currentRenderTargets.Resize(renderTargets.Count, false); | ||
| currentRenderTargets.Clear(); | ||
| currentRenderTargets.EnsureCapacity(renderTargets.Count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the other comment
| var resourceBindingsSpan = CollectionsMarshal.AsSpan(reflection.ResourceBindings); | ||
|
|
||
| // prepare resource bindings used internally | ||
| for (int i = 0; i < reflection.ResourceBindings.Count; i++) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my other comment about about using the span's length directly
| renderTargets.Resize(validatedTargetCount, false); | ||
|
|
||
| renderTargets.Clear(); | ||
| renderTargets.EnsureCapacity(renderTargets.Count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my other comment
| if (parameterKeyInfos[i].Key == layoutParameterKeyInfo.Key) | ||
| { | ||
| processedParameters[i] = true; | ||
| newParameterKeyInfos.Items[i] = layoutParameterKeyInfo; | ||
| newParameterKeyInfosSpan[i] = layoutParameterKeyInfo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parameterKeyInfos.Count -> newParameterKeyInfosSpan.Length
| var parameterKeyInfosSpan = CollectionsMarshal.AsSpan(parameterKeyInfos); | ||
| // Find existing first | ||
| for (int i = 0; i < parameterKeyInfos.Count; ++i) | ||
| { | ||
| if (parameterKeyInfos.Items[i].Key == parameterKey) | ||
| if (parameterKeyInfosSpan[i].Key == parameterKey) | ||
| { | ||
| return parameterKeyInfos.Items[i].GetObjectAccessor(); | ||
| return parameterKeyInfosSpan[i].GetObjectAccessor(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as other span length stuff
|
|
||
| private unsafe bool IsTetrahedronAllocated(int index) | ||
| private unsafe bool IsTetrahedronAllocated(int index, Span<Tetrahedron> tetrahedronSpan) | ||
| { | ||
| fixed (Tetrahedron* tetrahedron = &tetrahedralization.Items[index]) | ||
| fixed (Tetrahedron* tetrahedron = &tetrahedronSpan[index]) | ||
| { | ||
| return tetrahedron->Vertices[0] != -1; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Entire method body can be replaced by return tetrahedronSpan[index].Vertices[0] != -1;
| // Mark it as "unused" | ||
| fixed (Tetrahedron* tetrahedron = &tetrahedralization.Items[index]) | ||
| fixed (Tetrahedron* tetrahedron = &tetrahedronSpan[index]) | ||
| { | ||
| tetrahedron->Vertices[0] = -1; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tetrahedronSpan[index].Vertices[0] = -1;
| { | ||
| var tetrahedralizationSpan = CollectionsMarshal.AsSpan(tetrahedralization); | ||
| // Check connectivity | ||
| fixed (Tetrahedron* tetrahedra = tetrahedralization.Items) | ||
| fixed (Tetrahedron* tetrahedra = tetrahedralizationSpan) | ||
| { | ||
| for (int index = 0; index < tetrahedralization.Count; index++) | ||
| { | ||
| if (!IsTetrahedronAllocated(index)) | ||
| if (!IsTetrahedronAllocated(index, tetrahedralizationSpan)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, same as the rest
Replaces inefficient Clear() calls and Count-based loops with span-based operations using CollectionsMarshal.AsSpan for better performance. Updates affected code in ForwardRenderer, RenderOutputValidator, ImportModelCommand.Animation, and Effect to use spans for clearing and iterating over lists, and adds an obsolete overload in Dispatcher to guide usage towards array-based sorting.
Refactored BowyerWatsonTetrahedralization to eliminate unsafe code and pointer arithmetic, replacing them with direct access to Span and ref variables. This improves code safety, readability, and maintainability while preserving the original logic and performance.
Replaced Count-based loops with span Length in ParameterCollection for improved performance and correctness. Removed unnecessary Clear() call on SortedRenderNodes in RenderSystem as the collection is properly cleared in Reset().
|
Tweaked it a bit before merging, thanks for your work @Arc-huangjingtong |

PR Details
[FastList] is already obsolete ,but still has some code in project ,In the long run, someone has to do this
Related Issue
#2332
Types of changes
Checklist