logo of the comfy engine Comfy

Release v0.2: More Globals = More Comfy

2023-10-15

This is a second release of Comfy at version v0.2.0. In short it brings some API improvements, greatly improved default performance on integrated GPUs, and overall a lot of bugfixes & small performance improvements.

CHANGELOG

The main change in this release is that EngineContext is not necessary to pass around anymore. This should simplify a lot of the confusion, as the #1 question about Comfy from many people was about GameContext and EngineContext and why are there two any why do we even need them.

Since Comfy already uses globals for many things, it makes sense to just embrace this fully and move the remaining things to globals as well. Many of the values provided in EngineContext were already available through globals and just re-exported, so this shouldn't be a huge issue.

Comfy will still use EngineContext internally for some things, but this won't be re-exported to the users as everything should be accessible by other means.

List of removed things and where to find them now:

  • c.delta -> delta(). This is likely going to be something that most users (including us) will re-export into their GameContext/GameState anyway.
  • c.world() -> world(). ECS world already lived in a single instance, it's now moved into a single global.
  • c.commands() -> commands(). Same as above.
  • c.cooldowns() -> cooldowns(). This might be worth re-exporting into GameContext if accessed frequently, but in either way there's no extra overhead compared to before.
  • c.mouse_world -> mouse_world(). This already existed before, and may also be worth re-exporting anyway.
  • c.egui -> egui(). Note that before this was a field, now it's a global function. Though in this case egui::Context is already internally Arc<Mutex<ContextImpl>>, so this function is actually very cheap to call as it just returns a &'static egui::Context :)
  • c.egui_wants_mouse -> egui().wants_pointer_input()
  • c.config -> game_config() and game_config_mut().
  • c.cached_loader.borrow_mut() -> cached_loader_mut() (for & just omit _mut).
  • similarly c.changes.borrow_mut() -> changes() and c.notifications.borrow_mut() -> notifications(). The last three were undocumented and are not really intended for public use yet, but documenting them here anyway.

NOTE: Comfy still includes many APIs which are not currently documented but are still exposed. The current goal is to work through codebase and cleanup some odd bits and document them at the same time. If you find something that is not mentioned on the website or any examples, it's very likely to change in the future.

As a secondary note, it should be noted that comfy is still very early on in its lifecycle. Comfy will do its best not to break existing games, but we may need to iterate on some ideas, and some of them might be controversial, such as the use of globals.

Comfy is not a project ran by RFCs, and while we do appreciate feedback, some things have to be figured out by actually using the tool to build games, running benchmarks, and making decisions based on real world usage.

In our usage of Comfy we've found many things that many in the Rust community would consider "bad ideas" to be incredible boosts in ergonomics and productivity. This is something that seems to happen more often than not, and as such we're not really afraid to make changes like the above where a large portion of the state is moved into globals. If you find the above change unacceptable and what we had before "good", maybe take a look at the source code and see how many globals we already had :)

That being said, the #1 priority of Comfy is and always will be making real games. If any changes we make become problematic in real world use cases, please do report these. If you think something is slow, please submit a benchmark showing this. Comfy has enough examples using all of the systems, and a builtin integration with Tracy, so it should be easy to extend. We do care about reasonable games performing well on consumer hardware, but we do not care about being the fastest at rendering 500k particles.

Our own games are not locked behind on an ancient version of Comfy, and we're doing our best to stay up to date with the latest changes, to make sure things are actually working smoothly.

Bloom

Comfy v0.1.0 had bloom turned on by default. This turned out to be quite problematic on older integrated GPUs as some users reported, as the builtin bloom does 20 blur passes :)

In v0.2.0 bloom is now turned off by default. You can still enable it by calling game_config_mut().bloom_enabled = true;. There's also a new example that showcases bloom and how it can be configured.

Chromatic aberration

Comfy v0.1.0 also had chromatic aberration enabled by default, but considering this isn't even a documented feature and the API for using it is quite ugly we turned it off for now in v0.2.0. I don't think there's any chance anyone actually used it, but if you did, it'll come back soon I promise.

Post processing is one of the things that should improve after v0.2.0 is out, and we'll be able to add more effects and make them easier to use.

Asset loading

Comfy does include a parallel asset asynchronous asset loader, although the API isn't currently great and is going to be improved/changed in some ways. Related issues #42, #30, #36 for those that are curious.

An example of how this works can be found in the Comfy Asset Benchmark, but this issue remains relatively undocumented for the time being as there will be breaking changes around it.

The functionality is there and it is being used in production already.

Benchmarks

While Comfy is not an engine that focuses on speed, that doesn't mean performance is not important and shouldn't be tracked. There's now a WIP Comfy benchmark that includes both an asset loading benchmark, as well as a small comparison between Comfy and the official Bevymark, and also links to a few other references (e.g. Kha).

TL;DR: On my machine Bevy does ~120k sprites at 60FPS, Comfy does 35k, and Kha in a similar benchmark does 300k. We'd like to be as fast if not faster than Bevy with the next release :) It's unlikely Comfy will get anywhere close Kha, but there is no reason we shouldn't want to be a little bit faster than we're right now.

Again, it's not the goal of Comfy to be the fastest renderer in the universe, but being able to not think about "is this going to be slow" while writing gameplay code is important, so the aim should be to at least be as fast as the slower engines out there.

Minor changes:

  • GameConfig is no longer Copy. This shouldn't really affect anyone in any way, as it was behind a RefCell anyway.

First Comfy demo on Steam :)

Last week we released a demo of one of our smaller games on Steam. It's a Vampire Survivors clone called Unrelaxing Quacks, built 100% in Comfy and Rust, and can be played for free on Windows and Linux.

Next up

The global namespace is currently polluted by a lot of things. The next v0.3.0 release will focus on cleaning this up and making some things more directly accessible (e.g. some globals which are now currently not public).