I'm working with a company that's building a map-based application in Pixi. We have approximately 10k graphics objects on screen, up to 20k sprites (currently, with more planned in the future), and other various things that are displayed through HTML.
We're pretty much pegging our systems to the max with this (the application will pretty much refuse to run on my Intel HD laptop, even with culling). We've got some optimization in mind, but we wanted to check if there are any tips the devs may have for better performance under these circumstances? I can provide additional info as needed.
We were running a Pixi 3 implementation up until a few months ago, where we ported the application to use Pixi 5.
The quantity isn't really _much_ of an issue - even 20k can be done in a few draw calls depending on how smart you're being with your textures. The issue will be the GPU fillrate. You don't say what resolution the app runs in or what size those sprites are, but both are incredibly important. If you have a lot of overdraw going on then you may want to look at culling based on depth as well as the viewport. Based on these quantities, however, I suspect you're going to hit hardware limits faster than you'll hit browser ones.
So the resolution of the app is based on your browser window size; but let's say for argument's sake it's 1920x1080. We tried 4K at one point but that ran so badly we decided against it for now.
The sprites are actually SVGs, which I know Pixi doesn't support natively but instead converts them. What size they would be after conversion is hard to say, honestly.
As for your last point, we definitely have hit some hardware limits. We're looking into pseudo-multithreading some of the heavier calculations that we do, which should improve performance significantly. That's neither here nor there, though, when it comes to Pixi. When you say smart with your textures, though, how do you mean? Have any examples?
I am assuming that map-based means Google Maps/Mapquest style, and that those object counts are for the map as a whole, not just a typical subsection at normal zoom.
A culling optimization sometimes used in 3d video games is splitting the maps into "rooms" (in your case rectangles on the grid) so that if a room isn't visible they can cull the whole room instead of checking each object. In PIXI I would set this up as a parent(room) /child relationship and remove the parent from the stage entirely when out of view so that its contents don't get geometry updates when rendering. I don't remember if they are skipped when visible is false, but if that is the case then that toggle would be sufficient rather than add/removeChild.
Another optimization that could be used with the same grid based visibility detection is not having a Sprite/Graphics for each data element, but pooling the PIXI objects and assigning/reassigning them when a data element is actually in your viewport (or its grid rectangle is in the viewport). This strategy limits the number of objects getting geometry updates, but should save memory as well, I hope.
Severe zoom (like county level zoom with city/neighborhood based content) would require additional culling by having data elements having a minimum zoom at which they are displayed - this would work best with the pooling.
I'm working with a company that's building a map-based application in Pixi. We have approximately 10k graphics objects on screen, up to 20k sprites (currently, with more planned in the future), and other various things that are displayed through HTML.
We've got some optimization in mind, but we wanted to check if there are any tips the devs may have for better performance under these circumstances?
Tips ha-ha. 20k is serious. The first tip - use https://spector.babylonjs.com/ to see how exactly pixi puts your graphics in drawcalls, and how many webgl calls are there.
As for SVG, there are ways to represent it better:
Use pixi5-svg for huge objects, but beware of memory consumed by vertex buffers. They are really big compared to Flash. Here's the demo of what pixi5-svg can do: https://exponenta.games/games/map/ by @eXponenta (zoom out with mouse wheel)
If you have many small svg-s, dont rasterize in separate textures. There's a lib for v4 that can be ported for v5, you can ask us if you really want to do that: https://github.com/gameofbombs/pixi-super-atlas . Its possible to make runtime atlases based on it.
Overdraw. Performance for retina and resolution:2 is a problem, and you should definitely add two settings for both mac & windows users: 1. resolution 2. powerPreference, just in case they have 2 videos.
The task you are working on is very hard and its on bleeding edge. Don't expect tips that magically help you. Its huge work and so far universal solution wasn't found. I'm working on even bigger task for 3 years already, and I know that its possible to do all that stuff on Intel HD 3000.
My opinion - doing that kind of tasks without at least one person dedicated to low-level webgl problems/performance is just not possible. We can point the direction and where to get the current knowledge, but someone has to dig that tunnel under english channel on your side.
Thanks for the replies, all!
You're very right about the tips. Our thought today was "hey, we _are_ on the bleeding edge here, what are some things that we haven't considered when it comes to Pixi?". We may have someone to help us work on low-level stuff in the near future, including webGL. Our biggest bottleneck right now is definitely CPU-related, but that doesn't mean we aren't going to try to squeeze every inch of performance out of this thing. The hope is to eventually have a map as large as say, Manhattan, be viable and runnable at a stable framerate.
We're also discussing doing things on a grid-like basis for culling (and other things that just make sense for the project), and we may experiment with different methods of doing so. It's something we want to do, and hearing that it's perhaps a viable option is encouraging.
The links will make for excellent reading material for this afternoon.
We'll be looking into the suggestions that have been written here and any others that might come into the thread. This started us talking about various things we could implement, and it's honestly exciting! There were some things that we'd thought before but second guessed, so it's good to have other folks chime in and tell us we're not that crazy.
So again, thanks. This is super helpful, and we're going to start planning out the buying of shovels to dig that tunnel.
If you send me email at ivan.[email protected] I'll send you and invite to pixijs slack, that way you can be in contact with pixijs team and collaborators. There are several people who solved tasks like that partially.
Alternatively, you can add me in telegram (t.me/hackerham)
We're looking into pseudo-multithreading some of the heavier calculations that we do, which should improve performance significantly
Have you considered WebAssembly?