perf(transform): scale-only path, eager allocation, contain cache#14
Merged
Conversation
Follow-ups to the translate-only fast path: 1. Matrix3d.rotate(angle, out): guard angle===0 to skip Math.cos(0)/sin(0) and write an identity directly. Matches the existing instance-method guard. 2. updateLocalTransform: split rotation/scale into three branches — rotation (full multiply path), scale-only (4-mul .scale() in place), and translate-only. Avoids building a separate scaleRotate matrix and collapses the 8-mul multiply to 4 muls for the common UI-animation case of scale without rotation. 3. CoreNode now eagerly allocates localTransform and globalTransform as identity matrices in the constructor. The Global block reuses these instances via Matrix3d.copy(src, dst) instead of reassigning the field, keeping the field's hidden class stable. The dead `parent.globalTransform || lt` and `if (gt === undefined)` fallbacks are removed. _localIsTranslate now defaults to true since the eagerly allocated matrix is already identity-shape, so the very first update takes the fast path. 4. _hasContainResize cached on the node: updateIsSimple computes it once when texture/textureOptions change, and updateLocalTransform reads the boolean instead of running the optional-chain + string compare on every Local update. Stage root init updated to copy in place into the eagerly-allocated globalTransform rather than reassigning. Adds 12 unit tests covering: Matrix3d.rotate(0) identity output and reset semantics, scale-only path output (ta/td set, tb/tc untouched) including pivot algebra, constructor-time matrix allocation and instance reuse across simple/non-simple frames, and _hasContainResize flag transitions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
0da91e2 to
52d2c5d
Compare
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.
Summary
Stacked on top of #13. Follow-ups to the translate-only fast path:
Matrix3d.rotate(0)guard:Matrix3d.rotatenow skipsMath.cos(0)/Math.sin(0)(neither V8 nor JSC constant-folds them) and writes an identity directly.updateLocalTransformsplits the rotation/scale logic into three branches — rotation (full multiply path), scale-only (4-mul in-place.scale()), and translate-only. Avoids building a separatescaleRotatematrix and collapses the 8-mul multiply to 4 muls for the common UI-animation case of scale without rotation.CoreNodenow allocateslocalTransformandglobalTransformas identity matrices in the constructor. The Global block reuses these instances viaMatrix3d.copy(src, dst)instead of reassigning the field, keeping the field's hidden class stable. Deadparent.globalTransform || ltandif (gt === undefined)fallbacks are removed._localIsTranslatenow defaults totruesince the eagerly-allocated matrix is already identity-shape, so the very first update takes the fast path. Stage root init copies in place into the eagerly-allocated globalTransform._hasContainResize:updateIsSimplecomputes the boolean once when texture/textureOptions change;updateLocalTransformreads the flag instead of running the optional-chain + string compare on every Local update.Test plan
pnpm test— 132/132 passingpnpm build— cleanMatrix3d.rotate(0)identity output and reset semantics, scale-only path output (ta/td set, tb/tc untouched) including pivot algebra, constructor-time matrix allocation and instance reuse across simple/non-simple frames, and_hasContainResizeflag transitions🤖 Generated with Claude Code