Context
PR #2202 fixed the catalyst body snapshot fetch (corrected the TextureEntry type mismatch), which eliminated the bug where every catalyst fetch was being discarded and falling back to local rendering. However, when catalyst snapshots are unavailable (profile has no snapshots, fetch fails, etc.), the system still falls back to _async_capture_local, which:
- Instantiates an
AvatarPreview scene
- Re-assembles the full avatar with wearables
- Renders it off-screen via
async_get_viewport_image
- The viewport rendering (~300ms) still blocks the main thread during capture
While _async_capture_local is marked as async and uses await, the actual rendering operation is synchronous and causes frame hiccups.
Proposed Solution
Implement a proper async/background queue system for avatar profile generation:
Requirements
- True async rendering — Move the viewport capture off the main thread or use a frame-budgeted approach that spreads rendering across multiple frames
- Persistent queue — Queue requests for body/face snapshot generation that can be processed in the background
- Priority system — Visible/nearby avatars get higher priority than distant ones
- Cache integration — Generated snapshots should be cached with the same key structure as catalyst snapshots
- Graceful degradation — Impostors should render with a placeholder/silhouette until the snapshot is ready, rather than blocking
Implementation Ideas
- Option A: Render snapshots at reduced resolution (e.g. 128x256 instead of full size) to reduce main-thread time
- Option B: Use multiple small SubViewports and render one avatar part per frame, compositing the final image over several frames
- Option C: Offload to a background Godot instance (server mode) that renders snapshots and returns them via IPC/file
- Option D: Pre-generate snapshots for common avatar configurations during idle time
Related
Benefits
- Eliminates remaining frame hiccups from avatar appearance
- Better UX for users with profiles that lack catalyst snapshots
- More predictable performance in crowded scenes
- Allows for progressive loading of avatar quality
Requested by Mateo via Slack
Context
PR #2202 fixed the catalyst body snapshot fetch (corrected the
TextureEntrytype mismatch), which eliminated the bug where every catalyst fetch was being discarded and falling back to local rendering. However, when catalyst snapshots are unavailable (profile has no snapshots, fetch fails, etc.), the system still falls back to_async_capture_local, which:AvatarPreviewsceneasync_get_viewport_imageWhile
_async_capture_localis marked as async and usesawait, the actual rendering operation is synchronous and causes frame hiccups.Proposed Solution
Implement a proper async/background queue system for avatar profile generation:
Requirements
Implementation Ideas
Related
godot/src/decentraland_components/avatar/impostor/Benefits
Requested by Mateo via Slack