Skip to content

chore: opti: perf-hunt roll-up (#9693 #9697 #9700 #9701 #9702 #9703 #9705 #9706) - #9707

Merged
NickKhalow merged 28 commits into
devfrom
opti/perf-hunt/rollup
Aug 13, 2026
Merged

chore: opti: perf-hunt roll-up (#9693 #9697 #9700 #9701 #9702 #9703 #9705 #9706)#9707
NickKhalow merged 28 commits into
devfrom
opti/perf-hunt/rollup

Conversation

@NickKhalow

@NickKhalow NickKhalow commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Pull Request Description

What does this PR change?

Roll-up of the perf-hunt branches into a single integration PR for combined testing and merge. It includes the following PRs (each remains open for individual review; this PR supersedes them on merge):

Also in the perf-hunt series but not part of this roll-up:

See the individual PRs for per-change details, benchmarks, and test notes.

Test Instructions

Steps (standard run):

metaforge explorer run 9707

Expected result: No behavioral changes — the roll-up is fixes and work-reduction optimizations only. Key areas to sanity-check in one session:

Test Steps

  1. Crowded scene: avatars animate and outline correctly (own + remote), no skinning glitches when swapping spring-bone wearables (opti: skip redundant avatar layer weight writes and cache animator layer indices #9701, opti(avatar-rendering): bound bone-matrix job by each avatar's actual bone count #9705, opti(avatar-rendering): hoist frustum-plane extraction out of the outline query #9706).
  2. Teleport and reload a scene while pointing at something — no stale hand point-at (fix: reset stale hand point-at on teleport and scene reload (#9578) #9693).
  3. Roam landscape/ground terrain — no landscape rendering artifacts (chore: opti - reuse persistent native containers RenderSystem (landscape) #9697).
  4. Asset-heavy scene load — partial downloads complete normally (opti(web-requests): pre-size PartialDownloadHandler and grow geometrically #9703).
  5. Profile a session: reduced cost in AvatarShapeVisibilitySystem, BoneMatrixCalculationJob, and comms profile removal on idle frames (chore: opti(comms-profiles): skip the remove-intentions lock on empty frames #9700).

Quality Checklist

  • Changes have been tested locally
  • Documentation has been updated (if required)
  • Performance impact has been considered
  • For SDK features: Test scene is included

Code Review Reference

Please review our Branch & PR Standards before submitting. It explains the automated review flow, QA/DEV approval requirements, and what each label does — especially useful for first-time contributors.

eordano and others added 28 commits August 11, 2026 18:47
… bone count

BoneMatrixCalculationJob recomputed all MAX_BONE_COUNT matrices per avatar every frame regardless of how many ComputeSkinning actually uploads; refresh and pass through the authoritative per-avatar count so the job only computes the uploaded range.
Transform.SetPositionAndRotation is world-authoritative, so the resulting world pose equals the arguments passed in; skip the native position/rotation readback and assign the cache from them directly.
…stem

RenderGroundInternal allocated and disposed a NativeArray<int> and a NativeList<Matrix4x4> with Allocator.TempJob every frame the ground was visible; hold them as Allocator.Persistent fields instead, clearing them each frame and disposing once in OnDispose.
…cally

ReceiveData rented exactly PartialData.Length + dataLength and copied the full old buffer on every regrow, causing O(N^2) rent+memcpy churn over a chunked download. Pre-size the buffer from the Content-Length header when available, and otherwise double the buffer on regrow, copying only the bytes written so far.

Exercising the growth path requires driving DownloadHandlerScript's native callbacks, which has no stable unit-test seam in headless batch mode.
RemoteEntitiesExtensions.Remove ran every frame and unconditionally built an OwnedBunch<RemoveIntention>, whose ctor acquires MutexSync even when there is nothing to remove. Add a racy, lock-free NewBunchAvailable() pre-check (mirrors RemoteProfiles.NewBunchAvailable()) so the lock is skipped entirely on empty frames.
A cached absolute point-at world hit-point survived a teleport or same-realm
scene reload, leaving an avatar's arm pinned at a stale position. Reset the
point-at target from both the PlayerTeleportIntent path and the scene-reload
path (ECSReloadScene, both overloads).

Verified on real Unity 6000.4.0f1 (compile + EditMode/PlayMode regression tests).
…line query

GetAvatarsVisibleWithOutline recalculated the camera's frustum planes and re-fetched the camera component for every avatar; both are identical across a frame, so compute them once in Update and pass the camera in via [Data].
… writes

SetPointAtLayerWeight and SetRotationLayerWeight now shadow the last value written and skip the native Animator.SetLayerWeight call when it hasn't changed; ResetState clears the shadow so a rebind isn't skipped.
…ring-based lookups

Completes the layer-index scaffolding introduced with the weight guard:

- AnimatorEmoteLayers gains the BASE_LAYER_INDEX constant the scaffolding
  referenced (fixes compilation) and loses GetFromEmoteMask plus the
  unused ALL_LAYERS / NON_BASE_LAYERS arrays.
- GetAnimatorCurrentStateTag(string) and SetLayerWeight(string) resolved
  the layer via a native Animator.GetLayerIndex call on every invocation,
  per frame in HeadIKSystem and HandsIKSystem. All callers now use the
  cached index API (UpperBodyLayerIndex, GetEmoteLayerIndex, int
  overloads) and the string overloads are removed.
- Removes the unused DclAvatarMask using alias.
…oveIntentions.cs

Co-authored-by: Muna <44584806+decentraland-bot@users.noreply.github.com>
Signed-off-by: Nick Khalow <71646502+NickKhalow@users.noreply.github.com>
…ad-handler-growth' into opti/perf-hunt/rollup
@NickKhalow
NickKhalow requested review from a team as code owners August 12, 2026 14:19
@github-actions
github-actions Bot requested a review from DafGreco August 12, 2026 14:19
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

🚦 CI Status

Build

Windows and Mac build successful in Unity Cloud! You can find a link to the downloadable artifact below.

Name Link
Commit 74cdef8
Logs https://github.com/decentraland/unity-explorer/actions/runs/31606116205
Download Windows https://github.com/decentraland/unity-explorer/suites/85736290336/artifacts/9147183928
Download Windows S3 https://explorer-artifacts.decentraland.org/@dcl/unity-explorer/branch/opti/perf-hunt/rollup/pr-24919-74cdef8/Decentraland_windows64.zip
Download Mac https://github.com/decentraland/unity-explorer/suites/85736290336/artifacts/9147375181
Download Mac S3 https://explorer-artifacts.decentraland.org/@dcl/unity-explorer/branch/opti/perf-hunt/rollup/pr-24919-74cdef8/Decentraland_macos.zip
Built on 2026-08-12T15:19:42Z

Lint

Warnings count reduced: 13292 => 13202

Warnings/errors in files changed by this PR (104)
Assets/DCL/AvatarRendering/AvatarShape/Tests/PlayMode/BoneMatrixCalculationJobPerformanceTest.cs:81  AccessToDisposedClosure  Captured variable is disposed in the outer scope
Assets/DCL/Infrastructure/ECS/Unity/Transforms/Tests/PerformanceTests/SetWorldTransformCachePerformanceTest.cs:149  AccessToDisposedClosure  Captured variable is disposed in the outer scope
Assets/DCL/Landscape/Tests/PerformanceTests/GroundContainerReuse/RenderGroundContainerReusePerformanceTest.cs:196  AccessToDisposedClosure  Captured variable is disposed in the outer scope
Assets/DCL/Landscape/Tests/PerformanceTests/GroundContainerReuse/RenderGroundContainerReusePerformanceTest.cs:196  AccessToDisposedClosure  Captured variable is disposed in the outer scope
Assets/DCL/Landscape/Tests/PerformanceTests/GroundContainerReuse/RenderGroundContainerReusePerformanceTest.cs:197  AccessToDisposedClosure  Captured variable is disposed in the outer scope
Assets/DCL/Landscape/Tests/PerformanceTests/GroundContainerReuse/RenderGroundContainerReusePerformanceTest.cs:198  AccessToDisposedClosure  Captured variable is disposed in the outer scope
Assets/DCL/Tests/PlayMode/PerformanceTests/RemoveIntentionsFastPathPerformanceTest.cs:82  AccessToDisposedClosure  Captured variable is disposed in the outer scope
Assets/DCL/Tests/PlayMode/PerformanceTests/RemoveIntentionsFastPathPerformanceTest.cs:151  AccessToModifiedClosure  Captured variable is modified in the outer scope
Assets/DCL/Tests/PlayMode/PerformanceTests/RemoveIntentionsFastPathPerformanceTest.cs:202  AccessToModifiedClosure  Captured variable is modified in the outer scope
Assets/DCL/Tests/PlayMode/PerformanceTests/RemoveIntentionsFastPathPerformanceTest.cs:208  AccessToModifiedClosure  Captured variable is modified in the outer scope
Assets/DCL/AvatarRendering/AvatarShape/Tests/PerformanceTests/AvatarOutlineFrustumHoistPerformanceTest.cs:126  ArrangeRedundantParentheses  Redundant parentheses
Assets/DCL/AvatarRendering/AvatarShape/Tests/PlayMode/BoneMatrixCalculationJobPerformanceTest.cs:58  ArrangeRedundantParentheses  Redundant parentheses
Assets/DCL/AvatarRendering/Emotes/Systems/Play/CharacterEmoteSystem.cs:542  CSharpWarnings::CS8604  Possible null reference argument for parameter 'walletId' in 'DCL.Multiplayer.Emotes.IEmotesMessageBus.OnPlayerRemoved'
Assets/DCL/PluginSystem/Global/CharacterMotionPlugin.cs:54  CSharpWarnings::CS8618  Non-nullable fields 'settings', 'gliderPropPrefab', 'pointAtMarkerPool', 'destinationMarkerPrefab' must contain non-null values when exiting constructor. Consider adding the 'required' modifiers or declaring the fields as nullable.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:215  CompareOfFloatsByEqualityOperator  Equality comparison of floating point numbers. Possible loss of precision while rounding values
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:222  CompareOfFloatsByEqualityOperator  Equality comparison of floating point numbers. Possible loss of precision while rounding values
Assets/DCL/Character/CharacterMotion/Systems/HandsIKSystem.cs:107  InconsistentNaming  Name 'ApplyHandIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'ApplyHandIk'.
Assets/DCL/Character/CharacterMotion/Systems/HandPointAtSystem.cs:296  InconsistentNaming  Name 'ApplyPointAtIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'ApplyPointAtIk'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:47  InconsistentNaming  Name 'FeetIKRig' does not match rule 'members_should_be_pascal_case'. Suggested name is 'FeetIkRig'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:65  InconsistentNaming  Name 'HandsIKRig' does not match rule 'members_should_be_pascal_case'. Suggested name is 'HandsIkRig'.
Assets/DCL/Character/CharacterMotion/Systems/HandsIKSystem.cs:25  InconsistentNaming  Name 'HandsIKSystem' does not match rule 'members_should_be_pascal_case'. Suggested name is 'HandsIkSystem'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:79  InconsistentNaming  Name 'HeadIKRig' does not match rule 'members_should_be_pascal_case'. Suggested name is 'HeadIkRig'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:35  InconsistentNaming  Name 'HeadIKSystem' does not match rule 'members_should_be_pascal_case'. Suggested name is 'HeadIkSystem'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:66  InconsistentNaming  Name 'LeftHandIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'LeftHandIk'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:59  InconsistentNaming  Name 'LeftLegIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'LeftLegIk'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:55  InconsistentNaming  Name 'LeftLegIKTarget' does not match rule 'members_should_be_pascal_case'. Suggested name is 'LeftLegIkTarget'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:26  InconsistentNaming  Name 'RandomID' does not match rule 'members_should_be_pascal_case'. Suggested name is 'RandomId'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:73  InconsistentNaming  Name 'RightHandIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'RightHandIk'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:58  InconsistentNaming  Name 'RightLegIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'RightLegIk'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:53  InconsistentNaming  Name 'RightLegIKTarget' does not match rule 'members_should_be_pascal_case'. Suggested name is 'RightLegIkTarget'.
Assets/DCL/AvatarRendering/AvatarShape/UnityInterface/AvatarBase.cs:90  InconsistentNaming  Name 'TorsoIKRig' does not match rule 'members_should_be_pascal_case'. Suggested name is 'TorsoIkRig'.
Assets/DCL/Character/CharacterMotion/Systems/HandsIKSystem.cs:64  InconsistentNaming  Name 'UpdateIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'UpdateIk'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:160  InconsistentNaming  Name 'UpdateIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'UpdateIk'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:226  InconsistentNaming  Name 'UpdateIKWeight' does not match rule 'members_should_be_pascal_case'. Suggested name is 'UpdateIkWeight'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:92  InconsistentNaming  Name 'UpdatePreviewAvatarIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'UpdatePreviewAvatarIk'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:202  InconsistentNaming  Name 'UpdateRemoteIK' does not match rule 'members_should_be_pascal_case'. Suggested name is 'UpdateRemoteIk'.
Assets/DCL/AvatarRendering/AvatarShape/Components/MainPlayerPipeline.cs:21  InconsistentNaming  Name 'bonesTA' does not match rule 'non_public_members_should_be_camel_case'. Suggested name is 'bonesTa'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:37  InconsistentNaming  Name 'debugHeadIKIsEnabled' does not match rule 'non_public_members_should_be_camel_case'. Suggested name is 'debugHeadIkIsEnabled'.
Assets/DCL/Character/CharacterMotion/Systems/HandsIKSystem.cs:110  InconsistentNaming  Name 'handIK' does not match rule 'parameters_should_be_camel_case'. Suggested name is 'handIk'.
Assets/DCL/Character/CharacterMotion/Systems/HandsIKSystem.cs:109  InconsistentNaming  Name 'handIKTarget' does not match rule 'parameters_should_be_camel_case'. Suggested name is 'handIkTarget'.
Assets/DCL/Character/CharacterMotion/Systems/HandsIKSystem.cs:66  InconsistentNaming  Name 'handsIKComponent' does not match rule 'parameters_should_be_camel_case'. Suggested name is 'handsIkComponent'.
Assets/DCL/AvatarRendering/Emotes/Systems/Play/CharacterEmoteSystem.cs:464  InconsistentNaming  Name 'headIK' does not match rule 'parameters_should_be_camel_case'. Suggested name is 'headIk'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:92  InconsistentNaming  Name 'headIK' does not match rule 'parameters_should_be_camel_case'. Suggested name is 'headIk'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:163  InconsistentNaming  Name 'headIK' does not match rule 'parameters_should_be_camel_case'. Suggested name is 'headIk'.
Assets/DCL/Character/CharacterMotion/Systems/HeadIKSystem.cs:202  InconsistentNaming  Name 'headIK' does not match rule 'parameters_should_be_camel_case'. Suggested name is 'headIk'.
Assets/DCL/Character/CharacterMotion/Systems/HandPointAtSystem.cs:33  InconsistentNaming  Name 'isFreshPress' does not match rule 'members_should_be_pascal_case'. Suggested name is 'IsFreshPress'.
Assets/DCL/Character/CharacterMotion/Systems/HandPointAtSystem.cs:32  InconsistentNaming  Name 'isPressed' does not match rule 'members_should_be_pascal_case'. Suggested name is 'IsPressed'.
Assets/DCL/Character/CharacterMotion/Systems/HandPointAtSystem.cs:34  InconsistentNaming  Name 'pointerPos' does not match rule 'members_should_be_pascal_case'. Suggested name is 'PointerPos'.
Assets/DCL/AvatarRendering/AvatarShape/Components/MainPlayerPipeline.cs:22  InconsistentNaming  Name 'rootTA' does not match rule 'non_public_members_should_be_camel_case'. Suggested name is 'rootTa'.
Assets/DCL/AvatarRendering/AvatarShape/Systems/AvatarShapeVisibilitySystem.cs:106  InconsistentNaming  Name 'shouldPlayFootstepFX' does not match rule 'non_public_members_should_be_camel_case'. Suggested name is 'shouldPlayFootstepFx'.

…and 54 more (see the csharp-lint-reports artifact).

Tests

All Unity tests passed ✅

TESTS SUITE Result Passed Failed Skipped
EditMode ✅ Passed 24945 0 13
PlayMode ✅ Passed 236 0 36

@decentraland-bot decentraland-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

STEP 2 — Root-cause check

PASS. This roll-up addresses eight specific performance bottlenecks, each fixing the cause rather than a symptom:

  • Redundant bone-matrix computation beyond actual bone counts (#9705)
  • Per-avatar frustum-plane extraction repeated inside the query (#9706)
  • Redundant Animator.SetLayerWeight native interop calls (#9701)
  • Stale hand point-at surviving teleport / scene teardown (#9693)
  • Per-frame Allocator.TempJob native-container churn in landscape rendering (#9697)
  • Unnecessary managed→native round-trip in SetWorldTransform cache (#9702)
  • Linear buffer growth in PartialDownloadHandler (#9703)
  • Mutex acquisition on empty remove-intention frames (#9700)

STEP 3 — Design & integration

PASS with observations.

HandPointAtSystem subscription (#9693): The system subscribes to scenesCache.CurrentScene.OnUpdate in its constructor and unsubscribes in OnDispose(). This is the correct lifecycle pairing — the event signals scene teardown, which is the right moment to clear stale hand-pointing state. The currentSceneLost latch avoids component mutation inside the callback. One fragility: the code accesses scenesCache.CurrentScene at both subscription and unsubscription time rather than capturing the reactive property into a field. If the property ever returned different instances across the system’s lifetime (e.g., after a realm switch that recreates the reactive property), the -= in OnDispose would silently no-op, leaking the subscription and preventing GC of the system. See inline comment.

Owner search — HandPointAtSystem: The point-at lifecycle is already owned by HandPointAtSystem. The new subscription adds scene-loss detection to this same owner. No parallel lifecycle introduced. Checked: HandPointAtSystem is the sole creator/manager of HandPointAtComponent. The PlayerTeleportIntent query correctly uses an ECS component that exists only during teleport.

RefreshBoneCounts per-frame query (#9705): StartAvatarMatricesCalculationSystem.RefreshBoneCounts writes skinningComponent.BoneCount into the pipeline every frame. Bone counts change only on wearable re-equip, so this is technically “reconciling every frame what is known at an explicit moment.” However, the cost is one int write per avatar per frame (~100–200 iterations at peak), negligible vs. the subsequent Burst-compiled matrix job. The event-driven alternative would require cross-assembly wiring through the wearable equip pipeline. The query correctly filters [None(typeof(DeleteEntityIntention))]. Acceptable.

RenderGroundSystem persistent containers (#9697): The NativeArray<int> and NativeList<Matrix4x4> are rendering data containers, NOT entity/component collections. They do not violate CLAUDE.md §1. Disposal is correctly handled in OnDispose(). Lazy initialization via the nullable tuple is clean.


STEP 4 — Member audit

New public/internal members:

# Member Consumers Verdict
1 AvatarTransformMatrixJobWrapper.SetBoneCount(ref…, int) 1 (RefreshBoneCounts query) Data-push setter, not a derived predicate — OK
2 MainPlayerPipeline.SetBoneCount(int) 1 (wrapper above) Pipeline-internal forwarding — OK
3 RemoteAvatarPipeline.SetBoneCount(int, int) 1 (wrapper above) Has bounds check — OK
4 CalculateFrustumPlanes(Camera) 2 (Update + tests) Internal, narrowly scoped — OK
5 IsVisibleInCamera(Bounds) 1 (outline query) Signature narrowed from (Camera, Bounds) — OK
6 HandPointAtComponent.StopPointing() 2 (teleport + scene-lost) Encapsulates two operations — OK
7 IRemoveIntentions.NewBunchAvailable() 4 implementations Lock-free pre-check, well-documented — OK
8 IAvatarView.UpperBodyLayerIndex 2 (HandsIKSystem, HeadIKSystem) Replaces per-call GetLayerIndex(string) — OK
9 IAvatarView.GetEmoteLayerIndex(AvatarEmoteMask) 5 call sites Replaces AnimatorEmoteLayers.GetFromEmoteMask — OK
10 SetHiddenComponent (private→internal) Same call sites + tests Widened for testability — see inline note on single-flag invariant

No single-use→merge, absent≠false, or redundant-guard issues found.


STEP 5 — Line-level findings

All findings are P2 (no P0 or P1). See inline comments with suggestion blocks.

# Severity File Issue
1 P2 HandPointAtSystem.cs Subscription identity: capture the reactive property in a field to guarantee unsubscribe targets the same instance
2 P2 AvatarShapeVisibilitySystem.cs HasFlag→bitwise assumes single-flag callers; method is now internal. Add a debug assert
3 P2 PartialDownloadHandler.cs PartialData.Length * 2 can overflow int for buffers > ~1 GB. Use long arithmetic
4 P2 AvatarShapeVisibilitySystemShould.cs Test fields have double indentation (16 spaces instead of 8) on null!-annotated lines
5 P2 AvatarOutlineFrustumHoistPerformanceTest.cs Same indentation issue on null!-annotated fields

Security review: No security issues found. The ReceiveContentLengthHeader pre-allocation is correctly capped by PartialDownloadingRange.CHUNK_SIZE. The lock-free NewBunchAvailable() reads use atomic int reads with bounded one-frame staleness. No secrets, credentials, or injection surfaces.


STEP 6 — Complexity

COMPLEX. Touches the avatar rendering pipeline (GPU skinning, bone-matrix compute job), ECS systems, comms/multiplayer profile removal, landscape rendering with native containers, and scene lifecycle subscriptions across multiple assemblies.


STEP 7 — QA assessment

QA_REQUIRED: YES. Changes affect runtime avatar rendering (skinning, outlines, IK layers), landscape ground rendering, hand point-at behavior on teleport, and web-request buffer management.


STEP 8 — Non-blocking warnings

⚠️ CI: Test (playmode) failed — The failure is in “Log in to GitHub Container Registry,” an infrastructure issue unrelated to code changes. Edit-mode tests were cancelled as a cascade. Recommend re-running CI.

⚠️ CI: semantic / title-matches-convention failed — PR title opti: perf-hunt roll-up (…) may not match the repo’s allowed semantic types. Verify opti is an allowed type or adjust the title.

⚠️ Missing newline at end of fileAvatarOutlineFrustumHoistPerformanceTest.cs and RenderGroundContainerReusePerformanceTest.cs are missing a trailing newline.


STEP 9 — Verdict

REVIEW_RESULT: PASS ✅
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: Touches avatar rendering pipeline (GPU skinning, bone-matrix jobs), ECS systems, comms profile removal, landscape native containers, and scene lifecycle subscriptions across multiple assemblies.
QA_REQUIRED: YES


Reviewed by Jarvis 🤖 · Requested by decentraland-bot via GitHub

@balducciv balducciv left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build: v0.167.0-alpha-opti/perf-hunt/rollup-74cdef8
OS: macOS — M3, Windows 11

Scope: Roll-up of 8 perf/opti PRs (#9693, #9697, #9700, #9701, #9702, #9703, #9705, #9706). No behavioral changes expected — this is a smoke test to confirm no regressions across avatar rendering, landscape, teleport, web requests, and comms.


1. Avatar rendering — bone matrices, outlines, layer weights (#9701, #9705, #9706)

  • [ ✅ ] Enter a crowded scene (Genesis Plaza or similar) with 10+ avatars visible
  • [ ✅ ] Own avatar animates correctly — no skinning glitches or mesh distortion
  • [ ✅ ] Remote avatars animate correctly — no skinning glitches or mesh distortion
  • [ ✅ ] Avatar outlines render correctly (own + remote) when applicable (e.g. hover/selection outline if in build)
  • [ ✅ ] Equip/swap a wearable with spring bones (hair, cape, accessory) — no bone glitches after swap
  • [ ✅ ] Equip/swap a wearable with a different bone count than the previous one — no visual glitch on the transition
  • [ ✅ ] Play an emote — animator layers (point-at, rotation) transition smoothly, no stuck poses

2. Hand point-at on teleport/reload (#9693)

  • [ ✅ ] Point at an object/avatar with hand point-at active, then teleport — hand resets to neutral (no stale pinned arm)
  • [ ✅ ] Point at an object, then reload the current scene (same realm) — hand resets to neutral
  • [ ✅ ] Point at an object, then switch realms — hand resets to neutral
  • [ ✅ ] Repeat point-at → teleport a few times in a row to check for leaked subscriptions (no degraded behavior after repeated cycles)

3. Landscape rendering (#9697)

  • [ ✅ ] Roam across open ground/terrain outside scenes for a few minutes
  • [ ✅ ] No landscape rendering artifacts, flickering, or missing ground tiles
  • [ ✅ ] No visible hitching when ground comes in/out of view repeatedly (walk in and out of render distance)

4. Web requests / asset loading (#9703)

  • [ ✅ ] Load an asset-heavy scene (lots of textures/models) — assets load completely, no stalled/partial downloads
  • [ ✅ ] No broken/missing textures or models after load completes
  • [ ✅ ] Repeat with a slow/throttled connection if possible, to exercise the buffer-growth path

5. Comms / multiplayer profiles (#9700)

  • [ ✅ ] Join a scene with multiple other players present
  • [ ✅ ] Other players' profiles (names, wearables) load and update correctly
  • [ ✅ ] Players leaving/joining doesn't cause errors or stuck profile data
  • [ ✅ ] No increase in profile-related lag on idle frames (subjective — watch for stutter when no profile changes are happening)

6. General regression / log check

  • [ ✅ ] Player.log shows Loading stage: Completed for each scene load
  • [ ✅ ] No new exceptions tied to: HandPointAtSystem, RenderGroundSystem, PartialDownloadHandler, RemoteEntitiesExtensions, BoneMatrixCalculationJob, AvatarShapeVisibilitySystem, SetWorldTransform
  • [ ✅ ] No FPS/performance regression noticed subjectively during the above steps (bonus: profiler check if available)

Unrelated errors noted (do not affect verdict):
[List any noise per the standard exclusion list — GPUInstancerPro, DOTween, Curl error 42/23, shutdown ObjectDisposedException, etc.]

Verdict: PASS ✅

Note: a issue was found while testing this PR and will be filed as a separate issue
Context here

Player test 1-4.log
Player prod GP OK.log
Player second test.log
Player build test 1.log
Player build test 2.log
Player prod.log

Windows

Player.log

@NickKhalow NickKhalow changed the title opti: perf-hunt roll-up (#9693 #9697 #9700 #9701 #9702 #9703 #9705 #9706) chore: opti: perf-hunt roll-up (#9693 #9697 #9700 #9701 #9702 #9703 #9705 #9706) Aug 13, 2026
@NickKhalow
NickKhalow enabled auto-merge (squash) August 13, 2026 13:45
@NickKhalow
NickKhalow merged commit 01a17aa into dev Aug 13, 2026
35 of 44 checks passed
@NickKhalow
NickKhalow deleted the opti/perf-hunt/rollup branch August 13, 2026 13:45
eordano added a commit that referenced this pull request Aug 13, 2026
Both this branch and dev's perf-hunt roll-up (#9707) optimized the same
systems. Resolution: dev's shipped versions win where they subsume or refine
the branch's copy of the same optimization (AvatarShapeVisibilitySystem +
test, AvatarBase, HandPointAtSystem, RenderGroundSystem, TransformComponent,
PartialDownloadHandler); branch-unique changes kept (CharacterEmoteSystem
UpdateEmoteTags early-out, IRemoveIntentions doc). AnimatorEmoteLayers keeps
dev's trimmed shape plus BASE_LAYER, still needed by the branch's layer-index
perf test; that test's string-path arm now inlines the raw Animator calls the
deleted wrapper made, so the baseline measurement is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants