Problem. Pulsar's skeletal preview skinned vertices on the CPU and expanded indexed geometry on each pose. Change. I moved skinning to a WGSL vertex shader and retained GPU buffers across poses and LOD changes. Evidence. Parity and lifecycle tests passed, and an Intel N150 benchmark recorded lower CPU preparation and offscreen frame times.

The editor's skeletal preview originally did more work than it needed to when a pose changed. It skinned every vertex on the CPU, expanded indexed triangles and uploaded the resulting geometry. Even when the underlying mesh was identical, new frames repeated that preparation.

What changed

Before / CPU skinning

  1. Evaluate the pose
  2. Skin vertices and expand indexed triangles on CPU
  3. Upload the generated geometry
  4. Render the expanded mesh

After / GPU skinning

  1. Keep indexed bind-pose buffers resident
  2. Upload only changed joint palettes
  3. Skin vertices in the WGSL vertex stage
  4. Render through the existing preview path
Logical rendering paths. The diagram illustrates the change, not a captured editor frame.

The preview now retains static LOD buffers and rebuilds them when the mesh changes. Resource ownership also accounts for asset reloads and device recreation. I replaced the full CPU vertex-bounds scan with cached per-joint bounds. The cache can overestimate a pose's bounds, so framing may be less tight.

Runtime-driven previews use the same GPU path. The implementation keeps the existing normal-handling semantics for nonuniform scales instead of silently changing the visual result as part of an optimization.

Benchmarks, with the caveats

The published fixture uses an Intel N150 / ADL-N, 500,000 vertices and 128 joints. The offscreen frame comparison is synchronized at 256×256 and does not include native editor UI or presentation.

MeasurementBeforeAfter
Standalone CPU preparation55.416 ms0.025 ms
Pose upload65,999,736 bytes10,240 bytes
Synchronized offscreen frame98.998 ms16.261 ms
Scene GPU time5.391 ms11.955 ms

CPU preparation fell sharply, but the GPU did more work. The higher measured GPU scene time matters: these numbers support a speedup for this preview workload and machine, not a general claim that GPU skinning is always faster. The measurements are not a full native-editor frame-time benchmark.

Checking correctness and resource lifetime

I validated shader behavior against the prior CPU reference using GPU readback and rendering parity. The test set included an imported 34,159-vertex rig as well as resource-lifecycle cases on Intel Vulkan and llvmpipe. The change was also checked with 441 package tests, 11 importer regressions, compilation for affected targets, shader validation and scoped formatting.

The upstream PR records additional lint and test details. Metal, DX12, native input and forced device loss were not exercised in the reported validation, so I do not treat them as verified.

Code and methodology

Back to work