As the title says, could this be a use case for Bevy? Right now there aren't many good options, pretty much just react-native (which has many many flaws, I work with it all day) and Flutter. Once Bevy is supported on all platforms and has a rich UI framework would it be possible or sensible to use it for general app development? I've seen a few examples of this being done with Godot such as Godello. Having an all-platform all-rust tool to develop general purpose apps in addition to games would be amazing!
Godello makes for a cool demo but I have my doubts about using that technique for production apps any time soon. Game engines are built to maximize performance as consistently as possible whereas "normal" apps are very burst-y. Think about battery life for example, would you want a note-taking app to be maxing out your phone's CPU and draining your battery?
Even Flutter has performance issues with simple animations https://github.com/flutter/flutter/issues/31865.
In order to build "normal" apps Bevy would need a system that dynamically throttles the ECS to minimize CPU and GPU usage when animations aren't playing and the user isn't actively interacting with the app.
Considering that Bevy is extremely new and primarily focused on games I'd consider this to be "not anytime soon" 馃檪.
It might be good to start thinking about it now though. Unity has options for quality, and it might be good to add a config file for quality and performance. It could be used for simple things like limiting framerate to adding performance boosts in graphics pipelines. It could also be useful for adding developer defined performance boosts.
Apologies if this question(s) doesn't make sense as I don't know a lot about game engine design -- Why does a frame in Bevy where nothing changes have to use more CPU/GPU than an event loop tick in JS or Dart based native apps where nothing changes? If the contents of the screen aren't changing on most frames then why does CPU/GPU/battery usage need to be high? Does an engine like Bevy fully redraw every entity on every frame even if they're unchanged? If so, why, and does it need to be that way? Again sorry if these are naive questions and thanks for indulging my curiosity =)
Apologies if this question(s) doesn't make sense as I don't know a lot about game engine design -- Why does a frame in Bevy where nothing changes have to use more CPU/GPU than an event loop tick in JS or Dart based native apps where nothing changes? If the contents of the screen aren't changing on most frames then why does CPU/GPU/battery usage need to be high? Does an engine like Bevy fully redraw every entity on every frame even if they're unchanged? If so, why, and does it need to be that way? Again sorry if these are naive questions and thanks for indulging my curiosity =)
A large part of the difference is that game engines are generally immediate mode and browsers/apps are retained mode. Not saying it's impossible to have a mixture of both, I just want to outline the differences.
Retained mode apps can use various tricks to significantly reduce CPU/GPU usage. Most browsers (and apps) group UI elements together and render them to textures. Then they only need to render a handful of textures every frame. Imagine a web page with 100 UI elements, in most browsers they'd render all the elements to a single texture and then send that single texture to the GPU every frame. Much more efficient than sending 100 textures to the GPU. This is also why animation on the web can be tricky because if you're not careful you'll destroy this optimization and force the browser to render 100 individual elements every frame.
Game engines are much more interactive so they can't get away with the same optimization techniques. This is why graphics APIs like DirectX, OpenGL, etc. require the engine to send rendering data to the GPU every single frame.
Of course you could build a retained mode UI framework inside a game engine. In fact, this is exactly what Unity is doing with their new UI framework. However, this isn't a trivial task.
Here's an idea. What if we have a special UI element called a Container. This container would take all its children and render them to a texture (or multiple textures if the children are spread far apart). Internally this container would render a textured quad.
Animating this container would be super fast because you're basically just updating the material, and transform for a textured quad.
Of course, updating a child would require re-rendering the container texture. However, you can minimize this by optimizing your container hierarchy. Does a child animate frequently? Then just give that element its own container so that updating the container is cheap.
I like the sound of that. But instead of creating a separate type, what about making it a part of NodeComponents? It could be passed as a boolean like so:
NodeComponents {
energy_efficient: true,
material: materials.add(Color::rgb(0.04, 0.04, 0.04).into()),
..Default::default()
}
I think you're on to something. It would definitely be useful for large interfaces.
Again I might be off the mark here because I don't fully understand how rendering works, but might it be possible to automate the optimization with the mobx (transparent functional reactive) pattern?
This is what I use in react-native to have perfect render granularity (that is never render anything that hasn't changed) with zero boilerplate. The pattern essentially gives you a graph of exactly which nodes/components/functions depend on which data _without any explicit specification of dependencies_ and calls all dependent functions when a piece of data changes. Could that be used here to automatically group all unchanged elements into a single texture on each frame?
Mobx (especially mobx-state-tree) is absolutely the "killer" library for managing render performance in react (and Dart, there's an implementation for Flutter as well) https://mobx.js.org/README.html There's a rust implementation here: https://github.com/s-panferov/observe
I am not an expert in game development, but here is my thoughts on it.
If a game engine adds code designed to optimize a process, it automatically slows down the engine, by how much depends on what is being optimized. The hope of adding such code is that the small slow down will offer bigger benefits. It is an exchange of speed for efficiency or even more speed. However, if the engine is constantly updating, some optimizations prove to be useless and even detrimental.
I'm not sure whether or not mobx is designed for the speed of a game engine, but from your description it sounds like it runs every frame, which would probably be bad for a game engine. I could be wrong, but I don't think it would be useful. A container like the one CooCooCaCha mentioned would be useful for rendering since it essentially holds an image that only requires one faster render pass instead of potentially multiple, and only needs to update when something changes.
Thanks for mentioning it though, it does sound interesting and I think I will look into it for my own use.
I like the sound of that. But instead of creating a separate type, what about making it a part of
NodeComponents? It could be passed as a boolean like so:NodeComponents { energy_efficient: true, material: materials.add(Color::rgb(0.04, 0.04, 0.04).into()), ..Default::default() }I think you're on to something. It would definitely be useful for large interfaces.
That's true, you could make it built-in to all components. I wonder if the same system could be used for world-space UI.
Just a thought about quality and performance options. Bevy could implement a tier system for managing performance, similar to Unity's Low to Ultra quality tiers. It could use a similar syntax to Properties, but would allow for values to be swapped out based on the tier in use. Psuedocode:
CurrentTier = 1;
QualitySettings {
shader_quality: {
0: 128,
1: 256
2: 512
}
}
// in code
assert!(QualitySettings.prop_val::<u32>("shader_quality").unwrap(), 256);
It would also allow for enabling containers, and could have any number of tiers:
CurrentTier = 2;
QualitySettings {
energy_efficient: {
0: true,
4: false
}
}
NodeComponents {
energy_efficient: QualitySettings.prop_val::<bool>("energy_efficient").unwrap(), // would be equal to true
material: materials.add(Color::rgb(0.04, 0.04, 0.04).into()),
..Default::default()
}
I don't think something like this should be used under the hood, so that developers can make the choice of what they want to optimize, without worrying about it make choices for them or force them to use a config file. I think it is best used as a tool to make games more compatible with a variety of devices.
I think this is more than an energy efficiency setting though. Developers can use this system to optimize their UI's no matter what game, or app they are developing. Retained-mode UIs are seen everywhere, heck even Unity is moving their UI system to retained-mode. I suspect that this is because the efficiency gains are significant.
I agree that grouping elements should be optional and we should leave it up to the developer to use this system to optimize their UIs as they see fit.
I was just using energy efficient for lack of a better term. I think before something like this is implemented @cart and a few others should approve of this and offer feedback. I'm new to this engine (newer than a lot of people here), so I don't know what the current process is for getting something like this implemented into the engine. I really like the direction this is going.
Cool, I think we're on the same page. Curious what the other developers think when they have time.
I do want Bevy to be usable for non-game apps. We will be building the bevy editor as a bevy app, and we will want to limit its power consumption.
Bevy UI uses a "retained-mode" api (although we currently don't cache outputs). caching is something we will add eventually.
I think I will close out this issue as its too broad to be helpful for work-tracking, but do know that this is on my mind (and on the minds of other Bevy contributors). The Bevy Editor will probably be a forcing function for "energy-efficient apps".
Most helpful comment
Godello makes for a cool demo but I have my doubts about using that technique for production apps any time soon. Game engines are built to maximize performance as consistently as possible whereas "normal" apps are very burst-y. Think about battery life for example, would you want a note-taking app to be maxing out your phone's CPU and draining your battery?
Even Flutter has performance issues with simple animations https://github.com/flutter/flutter/issues/31865.
In order to build "normal" apps Bevy would need a system that dynamically throttles the ECS to minimize CPU and GPU usage when animations aren't playing and the user isn't actively interacting with the app.
Considering that Bevy is extremely new and primarily focused on games I'd consider this to be "not anytime soon" 馃檪.