Skepticism about Rendy

(Tatsuyuki Ishi) #1

Rendy has been out for a while, supporting our use of Vulkan. However, after trying to write a custom render pass for my game, I’ve become a bit skeptical of it.

My points are:

  • Rendy uses gfx-rs, which has multiple backends. I know that portability is important, but this has a few problems:
    • No Vulkan-specific libraries. Things like VMA are unavailable.
    • Heavy generics. I have not checked how it affects compile time, but generics have been a major cause of slowness in rustc due to the monomorphization scheme.
    • Portability is not free. While the goal is to run on a variety of platforms, Amethyst hasn’t really performed well on anything other than Vulkan. gfx-rs’s additional complexity doesn’t worth it at the moment (although there’s a big room of improvement).
      Viral suggested that a particular problem with gfx-rs is that backend behaviour is beyond what the types represent. Depending on the backend, unsupported operations might get emulated (slow path), panic, or even UB. An alternative is to properly provide feature detection, and allow the user decide to fallback or panic in those cases.
  • Rendy does more than a wrapper. Rendy calls itself “State of the art ‘build your own engine’ kit”, and this actually have two parts: ideas from Vulkan wrappers and concept from other game engines. Considering that docs are insufficient as described below, these additional concepts really creates confusion.
    Rendy’s design of graphs requires a lot of boilerplate. Compared to other wrappers, the graph boilerplate is so large that the overall example size becomes larger. You can check vulkano’s example for reference.
    At this point, it seems that Rendy needs to be separated clearly of these two: concepts from Vulkan, and concept originated and useful for engines. The former is required because gfx-rs is low level, and doesn’t provide facilities like destructor.
  • Lack of documentation. Rendy’s documentation is very minimal, and we probably need detailed guides in additional to the reference. Another thing we need is API design documents.
  • Seemingly poor maintainability. It’s rare but one of the files is over 3000 lines. I had a hard time examining this.
    Some part of the code doesn’t seem to be well coded. The chain crate have been very hard to understand. Good news is, this greatest offender is going to be removed as a part of the upcoming graph refactor.
  • Unsatisfied promises. The rendy README shows that Declarative pipelines is one of the goals, but it remains unimplemented. In the Amethyst use case we have so-called “submodules” for code separation, but they are not to the extent of being pluggable (can’t be integrated by end user). Writing render passes for Amethyst has a lot of frictions, so modularity is of great importance IMO.

And well, given that we have invested a lot of effort, I’ll try to avoid saying that we should just rewrite things. However, it might make sense to have some sort of diversity in design. I’m currently inclined to try out Vulkano to see how far can it go; especially because it has nothing in common with gfx-rs, and therefore has many interesting design choices.

1 Like
(Tatsuyuki Ishi) #2

I updated the post based on discussions from Discord.

I’d like to apologize to the gfx team as I had made some inaccurate statements.

1 Like
(Dzmitry Malyshau) #3

Hi there! I would like to address some points, mostly about gfx-rs.

No Vulkan-specific libraries. Things like VMA are unavailable.

Previously, we sketched an API that would allow VMA to be used on Vulkan backend internally. But in the end there isn’t much interest, since there is already rendy-memory that fills the same need and does it universally for all gfx-rs backends (instead of Vulkan only) in a non-intrusive manner.

Heavy generics. I have not checked how it affects compile time, but generics have been a major cause of slowness in rustc due to the monomorphization scheme.

Generics cause the compiler to spend time on each instantiation of them. In case of gfx-rs B: hal::Backend generic that everything depends on, this is precisely what you need. As for the other generics - they only slow down the compilation if you instantiate them differently. With Rendy, there is a consistent code path and only a single instantiation, so, again, generics are not a problem.

To back my words, we recently finished slimming down gfx-hal, and it only takes 8 seconds to build now from the ground up. We also sparked the process of slimming down Rendy and assisted in getting this done. I think @omni-viral and friends have done a great job at this front, and I don’t see this as a concern.

If you have measurements showing how building is (still) slow, please share, and we’ll see if it can addressed further.

Portability is not free. While the goal is to run on a variety of platforms, Amethyst hasn’t really performed well on anything other than Vulkan. gfx-rs’s additional complexity doesn’t worth it at the moment

Well, wgpu-rs does perform well. gfx-portability has also shown repeatedly to be efficient. We care a lot about performance and low overhead!

The limitations and issues hit by Amethyst may be related to Rendy (since wgpu-rs runs fine on Metal and D3D12), but I’m sure there are gears in motion to address them. In any case, you aren’t providing an alternative, unless you mean implementing Metal and D3D12 backends manually by Amethyst devs. This, naturally, could be faster than gfx-rs, but it requires significant engineering resources (and some amount of re-invention of what gfx-rs has).

Viral suggested that a particular problem with gfx-rs is that backend behaviour is beyond what the types represent

Of course, it’s totally unsafe, just like any other GPU API out there, with an exception of WebGPU. So again, I’m not sure how this is related to skepticism. The idea is that Rendy would set the invariants in place to use the GPU in a safe way.

At this point, it seems that Rendy needs to be separated clearly of these two: concepts from Vulkan, and concept originated and useful for engines.

Rendy is already represented by a bunch of semi-independent crates. I don’t know what else to wish here.

Rendy’s documentation is very minimal, and we probably need detailed guides in additional to the reference.
Seemingly poor maintainability.

These are all criticisms of Rendy on the surface, i.e. criticism of something that could be addressed by simply investing more engineering time into a project. This doesn’t sound like a criticism of the nature of what Rendy tries to do, and so I don’t think it should imply skepticism.

I’m currently inclined to try out Vulkano to see how far can it go; especially because it has nothing in common with gfx-rs, and therefore has many interesting design choices.

Ugh, reads like gfx-rs doesn’t have anything interesting, does it? Vulkano can be built on top of gfx-rs, and in fact this is mostly required one way or another to run on Metal and those Windows platforms without Vulkan support (e.g. Intel Haswell/Broadwell iGPUs), unless you completely drop support for these Windows machines and decide to use MoltenVK on macOS (which I assume would also need to be reviewed for code quality and design choices?).

5 Likes
(Tatsuyuki Ishi) #4

Well, I dug a bit further and it turned out this indeed is a problem. The problem is that it’s instantiated at the leaf product (user’s binary target). The issue when not using incremental is obvious: all instantiations are compiled again and again with each iteration. And incremental is not magic, actually: the current partitioning scheme requires a full recompile of all instantiations in the respective file when you add or remove any generic calls.

Requiring B: Backend everywhere, therefore, has serious drawbacks: the whole Amethyst renderer ends up being recompiled in cases like above.

BTW I tried benchmarking compilation with both rendy and vulkano examples, but since vulkano also uses a bit of generics on pipelines etc it seems incremental is not so effective in both crates. The rendy example took (time measured for the final binary target, not including any deps) more than twice longer (45s vs 15s) to do a clean build, and there are presumably two causes: one is that rendy is complicated, and another is due to instantiation.

Nah, it’s not about just safety, it’s about the backend’s implementation details leaking into end user code and contradicting what the API exposes. Users should not be required to do workarounds based on #[cfg].

For example feature detection is missing for recently-added normalized samplers: https://github.com/gfx-rs/gfx/blob/147b64c4432fe16ef2c866b20f538dc5686bc59d/src/hal/src/lib.rs#L60

Or swizzling not being supported on Metal: https://github.com/amethyst/amethyst/blob/10517e0b5c26e80c5e594785a520132726bd5e7c/amethyst_ui/src/glyphs.rs#L566

@omni-viral also mentioned memory objects as an example, where it becomes UB if you alias them on wgpu or opengl. I think he knows more so you could ask him for more cases.

In addition to feature detection, it makes sense to offer type constraints so that you don’t end up with a panic inside gfx when something is not supported.

Fair. Rendy currently misses a considerable amount of safe wrappers, and that’s one of the motivation I raised Vulkano. I think if it’s implemented though Rendy is probably on par with Vulkano.

(Dzmitry Malyshau) #5

Great reply here, thank you for sharing the experiments in building Vulkano and Rendy!

The cases you provide for #[cfg] feature detection are just TODO things. It’s by no means that gfx-rs is designed for the users to have #[cfg]. Instead, it’s that we haven’t reached a state where we are exposing all of the limitations.

Again, this isn’t a problem with just gfx-rs itself. It’s not like you are magically going to get swizzles on Metal when running via Vulkano/MoltenVK. This is why Vulkan Portability Initiative exists - to expose these limitation in a way that people could query reasonably at run/init time. We are active contributors to this technical subgroup, we are basically on the spear end of nailing this.

1 Like
(Tatsuyuki Ishi) #6

Since I happened to be confused and got an answer from @kvark:

wgpu only depends on rendy-memory and rendy-descriptor, and basically can be considered not to be something very tightly coupled with rendy.

Apparently… Amethyst is almost the only user of rendy (including graph)? This is a little bit alarming since there would be no interest outside Amethyst to maintain rendy-graph and I’m afraid we can’t expect a lot of careful consideration in API design.

(Erlend Sogge Heggen) #7

Can you elaborate on that? I fail to see how this follows.

(Tatsuyuki Ishi) #8

First the audience is small and Amethyst is short of resources, so I’m skeptical that sufficient discussion would take place.

Second when rendy is so tightly coupled with Amethyst it might as well be inside the Amethyst main repo’s tree. I mean that in that way rendy’s change will be completely driven by Amethyst, and in this way it’s more like a workspace member rather than middleware.
I believe this is already true given most Rendy PRs has an associated Amethyst PR/issue.

(Gray Olson) #9

I really don’t see how any of the latest points about rendy’s public use are a concern. I mean of course we would like more users in rendy to gather more feedback etc, but, in the case you call this a dealbreaker about rendy, you would have to say the same about the entirety of Amethyst. We do the best to engineer each things we use as well as we can; rendy is no different. It’s ‘owned’ by the amethyst project and is primarily worked on by our members, it’s already under the github org. It’s not part of the main amethyst repo because there is no reason for it to be; like laminar, atelier-assets, etc, in theory, it’s a great ecosystem resource and can be easily used outside of Amethyst proper, if and when we get it to a point where it’s attractive to others.

6 Likes
#10

For what it’s worth, I’m using rendy in a non-amethyst-related project. The library still feels young and I suspect it will go through many major changes before it can be considered mature, but I think that’s completely normal for something as ambitious as what rendy is intended to be.

4 Likes
(Fletcher) #11

There is nothing in this thread that convinces me that it would be worthwhile to change rendy and/or hal. Any discussion about doing so is going to have to go something like this:

  1. Define what we want out of a renderer
  2. See what is missing from rendy and/or hal
  3. Estimate the work required to bring rendy/hal inline with the requirements
  4. Estimate work required to write a new one

And these will have to be thoughtful discussions, not off-the-cuff “I don’t like this one thing in rendy, so I’m going to make a post about it”. Switching to rendy nearly killed this project due to the time and effort required; another year+ doing it again simply will not happen.

This topic is a non-starter. If anyone wants to bring it up again for serious discussion, you can ping me and we’ll talk about it first. Everyone’s time and energy is better spent elsewhere.

5 Likes