arkavo-org / arkavo-org/VRMMetalKit

Per-frame render-item string classification and cache inefficiency

Open
#216 0 comments 0 reactions 0 assignees View on GitHub
high performance
Dominant language
Swift
Stars
6
Forks
2
Avg merge
18h 51m
Merged PRs (30d)
26

Description

## Summary
The render loop performs heavy string classification (`lowercased()`, `contains(...)`) on a per-primitive basis every frame. Additionally, transparent items rebuild a Z-sort dictionary every frame, and `EncoderStateCache` is underutilized because render items are sorted by `renderOrder` (face categories) rather than by pipeline state.

## Impact
- ~10–15 `contains(...)` checks per primitive → ~1,500 string searches/frame for a 100-primitive model.
- `viewZByIndex` dictionary cleared and repopulated every frame.
- Frequent pipeline state switches because skinned/non-skinned and opaque/blend items are interleaved.

## Location
- String classification: `VRMRenderer.swift:1585–1799`, `:2533–2537`, `:3044`
- Z-sort rebuild: `VRMRenderer.swift:1844–1849`
- State cache bypass: `VRMRenderer.swift:3669` (outline pass)
- Sort order: `VRMRenderItemBuilder.swift:267–280`

## Evidence
```swift
// Rebuild every frame
viewZByIndex.removeAll(keepingCapacity: true)
viewZByIndex.reserveCapacity(blendCount)
for item in allItems where item.materialRenderQueue >= 2500 {
viewZByIndex[item.primitiveIndex] = (viewMatrix * worldPos).z
}
```

## Suggested Fixes
1. **Pre-compute category bitflags at load time** (`isFace`, `isBody`, `isEye`, etc.) and store them on `RenderItem`. Eliminates all runtime string matching.
2. **Reuse Z-sort array** instead of a dictionary; use a stable sort or radix sort.
3. **Sort by pipeline state within each render-order bucket** (opaque skinned → opaque static → blend skinned → blend static) to maximize `EncoderStateCache` hit rate.
4. **Route outline pass through `EncoderStateCache`** instead of direct `setRenderPipelineState`.

Contributor guide

Open the contributing guide

Research direction

Start in VRMRenderer.swift at lines 1585–1799, 1844–1849, 2533–2537, 3044, and 3669, then inspect VRMRenderItemBuilder.swift:267–280 and the RenderItem definition. Trace how categories, transparent-item depth data, sorting, and EncoderStateCache are used across the render loop. Done means the selected optimizations are implemented consistently and per-frame string searches, dictionary rebuilding, and avoidable pipeline-state cache bypasses are removed without changing render ordering or output.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
computer-graphics, performance
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.