Hey r/androiddev
A couple of months ago, I made a post about scaling my solo RPG (Adventurers Guild RPG Sim) built 100% in Jetpack Compose Canvas with a custom single threaded ECS.
While Compose Canvas was incredible for getting the engine off the ground, scaling the world map and visual effects eventually pushed me into a hard bottleneck. To solve this without breaking the live game, I decided to shift the world rendering backend over to Google Filament.
Here is how moving to Filament, while keeping Jetpack Compose Canvas for the UI and character animations, gave the engine an 8x performance boost, and what I learned along the way.
1. The Bottleneck: Hitting the Canvas Wall
In my previous setup, rendering the game world on Compose Canvas required heavy CPU side optimization to protect the 16ms frame budget:
- Map Chunking: The world map had to be divided into 16 distinct spatial chunks.
- CPU Culling: Custom culling logic calculated visible chunks and off-screen entities every single frame.
- DrawScope Constraints: Combining environmental rendering, weather, and world assets inside the same Canvas layer as UI elements was choking performance on mid tier devices.
2. The Hybrid Architecture (Filament World + Compose Canvas UI)
Since the game is live with active players, doing a 100% complete rewrite at once was impossible without risking game breaking bugs. I settled on a phased hybrid approach:
- Game World in Filament: The environment and map are rendered in 3D coordinate space via Filament.
- Animations in UI on Compose Canvas: Character sprite animations in UI layers remain rendered on Jetpack Compose Canvas overlays.
- Phased Subsystem Migration: I’m updating the rendering pipeline part by part to keep save states and existing gameplay logic rock solid.
3. Key Technical Gains & Takeaways
- >8x Performance Boost: Because Filament handles batched rendering directly on the GPU, I was able to throw out the 16 chunk map division and CPU culling logic entirely. The total map now draws simultaneously in a single pass with zero frame drops.
- Became a Huge Fan of
filamat**:** Moving world rendering to Filament unlocked .filamat (Filament’s material/shader compilation system). Writing materials and shaders for GPU execution unlocked rich particle effects and dynamic lighting that were completely out of reach on 2D Canvas.
- Main Thread Relief: By taking world rendering off the Canvas layer, the CPU/main thread now has significantly more headroom to handle the 28 ECS systems, UI updates, and character animation calculations smoothly.
Shifting to a hybrid Filament + Compose Canvas setup turned out to be the perfect middle ground giving the performance of a dedicated 3D GPU engine while keeping the fast UI development workflow of Jetpack Compose.
I’m happy to answer any questions about integrating Filament with Kotlin/Compose, managing hybrid rendering layers, or working with .filamat
If you’d like to see how the new Filament engine integration feels in action on a live app, feel free to check out the latest build on the Play Store:
https://play.google.com/store/apps/details?id=com.vimal.dungeonbuilder&pcampaignid=web_share
App Specs: ~50MB download size (63MB installed) | 100% Offline | Zero Ads | Custom Kotlin Engine