perf: Cache the rotation and skip redundant work in Transform2D - #4024
Open
spydon wants to merge 3 commits into
Open
perf: Cache the rotation and skip redundant work in Transform2D#4024spydon wants to merge 3 commits into
spydon wants to merge 3 commits into
Conversation
Cache the sine and cosine of the angle so that matrix recalculation after position, scale or offset changes no longer recomputes them, keep the assigned matrix instead of recomputing it after the transformMatrix setter, batch the scale and position notifications in that setter, and avoid repeated reads in the point conversion methods. Adds a Transform2D micro-benchmark. Claude-Session: https://claude.ai/code/session_01H6f6E3vr3DM6iAWskqXpQT
Keeps the transform matrix bit-identical to the previous implementation, which the snapshot golden depends on. Claude-Session: https://claude.ai/code/session_01H6f6E3vr3DM6iAWskqXpQT
erickzanardo
approved these changes
Aug 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Makes
Transform2Dcheaper on its hot paths without changing its API or behavior:cosandsin, even when only the position, scale or offset had changed, which is by far the most common case (a component that moves every frame).transformMatrixsetter no longer throws away the matrix it was just given. It set_recalculate = falsebefore updating the scale and position, whose listeners flipped it back totrue, so the next read recomposed the matrix from the decomposed values. It now keeps the assigned matrix, and it updates the scale and position with onesetValuescall each instead of two separatex/yassignments, halving the number of notifications going out to their listeners.setFromcopies the fields directly (including the cached rotation) instead of going through the public setters, andTransform2D.copyis built on top of it.localToGlobalandglobalToLocalread each matrix cell and point coordinate once instead of repeatedly, andhasReflectionno longer goes through.sign.A
transform2d_benchmark.dartsuite is added topackages/flame/benchmarkso that these paths can be tracked going forward. Every case runs 1000 iterations perrun.Benchmarks
Times are per
run(1000 transforms or point pairs), median of three rounds.AOT (
flutter run --releaseon an arm64 Android emulator, API 34, Apple Silicon host):JIT (
flutter test benchmark/transform2d_benchmark.dart, macOS, Apple Silicon):The angle-update case is expected to stay flat since changing the angle still has to recompute the trigonometry; the point is that all other property changes no longer pay for it. The remaining cost of the position-update case is dominated by the
ChangeNotifierround trip fromNotifyingVector2intoTransform2D, which is out of scope here since theVector2implementation is about to change.One thing worth noting for future work on this class: an earlier iteration of this PR inlined the recalculation check directly into
localToGlobal/globalToLocalvia a private_recalculateMatrix()method, and that made the point-conversion case about 50% slower under the JIT (76 µs vs 49 µs) while being neutral in AOT, presumably from the cold call site being inlined and bloating the hot methods. Going through thetransformMatrixgetter, as the code did before, keeps both compilers happy.Checklist
docsand added dartdoc comments with///.examplesordocs.Breaking Change?
https://claude.ai/code/session_01H6f6E3vr3DM6iAWskqXpQT