perf(tween): native Godot Tween for Move/Rotate/Scale [prototype, draft]#2170
Draft
manuelmaceira wants to merge 3 commits into
Draft
perf(tween): native Godot Tween for Move/Rotate/Scale [prototype, draft]#2170manuelmaceira wants to merge 3 commits into
manuelmaceira wants to merge 3 commits into
Conversation
Adds --native-tween CLI flag. When enabled, SDK7 Tween components with Move / Rotate / Scale modes are migrated from the per-frame Rust interpolation + CRDT re-dirty loop to Godot's native Tween (RefCounted, RID-based, no Node overhead per tween). Mechanics: - setup_native_tween(): on first frame of an eligible tween, creates a Gd<Tween> via node.create_tween() configured with the mapped Godot TransitionType + EaseType. For Move with face_direction, sets the rotation upfront then tweens position only. - Main loop: for native-active tweens, only polls is_running() to emit TweenState on transition (TsActive -> TsCompleted / TsPaused). Skips all per-frame interpolation math and the CRDT.put + dirty injection. - On completion: writes the final transform back to CRDT (so SDK7 readout matches the rendered pose) and drops the Gd<Tween>. - On reset / delete / mode change: kills the existing Gd<Tween>. Continuous and TextureMove modes remain on the Rust path — they need per-frame delta-time / UV callbacks that don't map cleanly to property tweens. Toggle: --native-tween (default OFF). Bench A/B not yet measured.
…rivers Gates update_tween + update_animator (Rust early-return) and sweeps the scene tree at warmup entry setting every AnimationPlayer / AnimationTree active=false + callback MANUAL. Measures the animation-free frame ceiling.
7 tasks
Contributor
📦 Build Report🤖 Android
Build Status: ✅ Success 🍏 iOS
🔗 Workflow Run: View logs 🔄 Updated: 2026-05-26 17:33:05 UTC |
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.
What
Prototype migrating SDK7
TweenMove/Rotate/Scale modes from the per-frame Rust interpolation loop to Godot's nativeTween(RefCounted, no Node overhead). Stacked on #2025 (perf stack).Draft — perf-neutral on Genesis Plaza; kept as an architectural reference + the diagnostic flag it produced. See findings below before merging.
Changes
--native-tweenflag (default OFF, deeplinknative-tween=true). When on, SDK7 Tween components with Move/Rotate/Scale modes are driven by aGd<Tween>created vianode.create_tween(), configured with the mapped GodotTransitionType+EaseType. Eliminates the double-pass (Rust calc → CRDTput→ re-dirty →transform_and_parentapply); Godot processes all active tweens in one C++ loop.setup_native_tween()builds the tween on first frame; the main loop only pollsis_running()to emitTweenStateon transition.Gd<Tween>.kill()the existing tween.--kill-animationsflag (default OFF, deeplinkkill-anims=true) — diagnostic. Gatesupdate_tween+update_animator(Rust early-return) and sweeps the scene tree at warmup setting every AnimationPlayer/AnimationTreeactive=false. Measures the animation-free frame ceiling.Bench findings (A54, HIGH, GP ea9cc738)
native-tween A/B
Perf-neutral. GP barely uses SDK7 Move/Rotate/Scale tweens — its animation load is 144 AnimationPlayers + AnimationTrees (glTF/avatar), a different subsystem. The fogata (16 fire particles × Move+Rotate+Scale via
createOrReplace) is the heaviest SDK7-tween user and renders identically with native ON (correctness validated visually), but ~48 tweens is too few to move the frame. Native tween would win on a scene with hundreds of long-lived concurrent tweens; GP isn't that scene.kill-animations diagnostic (counterintuitive)
Disabling all 209 AnimationPlayer/Tree nodes made perf worse: GP's animations do implicit culling (scale-to-0 particles, visibility tracks, off-screen motion). Frozen at bind-pose, that geometry strands on-screen → +30% primitives. Animation is not the bottleneck in GP — it's the raw primitive/draw count (geometry: tris, LODs, mesh dup). Confirms the scene-side GLTF audit is where the real lever is.
Recommendation
Don't merge for perf — it's net-neutral on GP. Options:
--kill-animationsdiagnostic flag is worth keeping regardless (cheap, gated, useful for future profiling).Test plan
cargo clippy --release -- -D warningsclean.