three-d icon indicating copy to clipboard operation
three-d copied to clipboard

WGPU Backend

Open NHodgesVFX opened this issue 2 years ago β€’ 18 comments

It would be cool to have a WGPU backed for a couple of reasons

  • GLOW uses OpenGL which is deprecated on Apple platforms
  • OpenGL, although still extremely relevant, is a previous gen technology.
  • GLOW uses OpenGL 3.3 (According to the readme of three-d) for its max spec which misses features which are used a lot today like compute shaders.
  • GLOW will likely not support WebGPU, which will greatly expand the power of 3d on the web.
  • WGPU supports WebGpu, WebGL2, OpenGL, Vulkan, DX11, DX12, and Metal
  • Although it does not now WGPU in the future could support Raytracing.
  • WGPU in theory may be faster then GLOW when using the Vulkan, DX12, Metal, and WebGPU back-ends

There is another framework https://github.com/BVE-Reborn/rend3 that is similar to this one that uses WGPU as its back-end but it is a lot more verbose compared to this library.

Thanks for offering a really cool and simple to get started 3D Library in rust :)

NHodgesVFX avatar Apr 01 '22 21:04 NHodgesVFX

Thanks for the kind words πŸ™

It would be cool with other backends and I have considered it, I even planned for it. However, I'm not sure how much benefit it will do right now compared to the amount of work (but please prove me wrong). Also, I'm not sure about WGPU as opposed to directly using WebGPU, Metal, Vulkan etc. but I will definitely consider it if it becomes relevant. However, first, I need to be convinced that another backend is worth the trouble πŸ™‚

So to explain my opinion, please keep in mind the purpose of three-d which is to make it simple to draw stuff. This is great for visualisation, tools, simple games etc. but if you want to make a AAA game, you probably want to use something else. Also keep in mind that it should be possible to write your own shaders and combine high-level features with low-level graphics calls which complicates adding another backend.

GLOW uses OpenGL which is deprecated on Apple platforms

This is definitely a good argument for making a Metal backend, but OpenGL is still working, so not super urgent.

OpenGL, although still extremely relevant, is a previous gen technology.

OpenGL is, as you said, still relevant and still the most cross platform graphics API and on some platforms the standard graphics API. For me, that it's old, is not an argument that would make me do a lot of work.

GLOW uses OpenGL 3.3 (According to the readme of three-d) for its max spec which misses features which are used a lot today like compute shaders.

I specified 3.3 since that corresponds to webgl2 and I can therefore write the same code (almost). I'm curious to know what you want to use compute shaders for? Also, please keep in mind the purpose of three-d.

GLOW will likely not support WebGPU, which will greatly expand the power of 3d on the web.

GLOW will definitely not support WebGPU. Again I'm curious as to what features you are missing? And again, think of the purpose of three-d.

WGPU in theory may be faster then GLOW when using the Vulkan, DX12, Metal, and WebGPU back-ends

It's true that you can get a performance gain if using a modern graphics API, but I would always look at the code and hardware first. How much you gain will depend on the platform, some might give a significant speed-up (I'm guessing apple products). However, modern graphics APIs tend to be more complex and that complexity will either be reflected in three-d, making it less simple to use, or some of the performance gain will be lost to keep it simple. And again, the purpose is not to cater for AAA game companies, so the small performance gain is not important compared to keeping the crate simple to use (that's not saying performance is not important, just that the graphics API is not the main source of performance problems).

asny avatar Apr 03 '22 18:04 asny

I think there are some good points in support of wgpu.

  1. debugging builtin with wgpu. trace feature + debug_groups.
  2. crashes instead of segfault if there's some bug
  3. has huge community backing in rust. three-d can eventually use other crates to delegate some features like text rendering etc..
  4. safe (or rather, no unsafe except for a couple functions at startup). no global state either.
  5. single api for both web and native.

one obvious issue is that its still not final and breaking changes every few months.

opengl is

  1. unsafe
  2. could segfault at any moment if there's an error. no panics :(
  3. has its features / api split across a wide variety of hardware / platforms (web or native or es). compute shaders feature is a good example which doesn't exist on web, as well as varied behavior like glow's create_buffer being gen_buffer on desktop which doesn't set the buffer state on creation, while webgl's create_buffer does, while modern opengl 4.5 desktop has its own create_buffers function which behaves similar to webgl's counterpart. https://stackoverflow.com/questions/31841494/difference-in-glgenbuffers-and-glcreatebuffers which might lead to about platform / hardware specific workarounds = more maintenance burden.
  4. is old. thus, companies like amd are very slow to fix any bugs in their drivers. and drivers are pretty hit or miss on windows.

I definitely think opengl backend should be the priority for now as wgpu is still unstable. but having wgpu backend is cool because

  1. it doesn't have any global state (so, won't affect three-d if we just pass the device / context to users for any custom drawing).
  2. easier maintenance due to easier debugging + single api across platforms + less unsafe + using external crates which use wgpu to delegate features.
  3. wgpu aims to have a glow backend in the future. so, when it happens, three can drop opengl backend.

EDIT: I just found three-d looking for an 3D rendering crate. there's LOTS of 2d rendering libs in rust, but only rend3 or three-d for 3D rendering atm. my use case is just egui + few gltf scenes + a lot of billboards + lua scripting for plugins. for simple cases like draw rectangle and more complex but common cases like pbr gltf scenes, i would like to use a rendering crate (and allow lua plugins to use it too). but for specialized cases like billboards, and whether they need to be displayed or not, and generation of meshes, i would like to compute shaders or other features like draw_count_buffers / multi indirect drawing to improve performance. idk if three-d aims to support such use cases, but thought i should provide an example for the sake of this issue.

coderedart avatar Apr 19 '22 07:04 coderedart

Thanks for the input @coderedart πŸ‘

First of all, I hope that I got the right message across with the first reply; I definitely think it is a good idea with other backends. My sole concern is that it is a lot of work (all shaders has to be reimplemented for example) and that it will limit other development efforts, but it is difficult to know exactly how bad it is. Could be interesting to make a quick proof of concept though.

I didn't (and I still haven’t) looked much into WGPU, I just follow it at a distance, so nice with some insights. Could be really nice to have one API instead of implementing a lot of different backends, so it is quite attractive, but it sounds like it needs to be a bit more stable.

Compute shaders are definitely nice to have, but unfortunately they are not available everywhere yet, so I’m unsure how I can support them without dropping support on some platforms or having specific behaviour for different platforms which wouldn't be nice from a user perspective. Also, I think you can draw millions of billboards with three-d (if you haven't found it, billboards are Sprites with None as direction), if not more, before you get into performance problems, especially if you use deferred rendering. But maybe I misunderstood your use case. Generating meshes is a great use case but it is quite rare that it is not possible to create them offline on the cpu and upload them to the gpu (ie. the classic way) or alternatively on-demand in parallel on the cpu and then upload it (which is also quite fast). So, compute shaders are nice to have, not a blocking feature, as I see it πŸ™‚

asny avatar Apr 20 '22 18:04 asny

At least for me the appeal of compute shaders and my use case for them is to be able to simulate large numbers of particles in real-time. I didn't realize glow actually supports compute shaders, if you were going to implement them I would just make it so they all have the same interface, that way the user doesn't need to figure out what function to call on what platform. If the user is on a platform / OpenGL version that doesn't support compute shaders then just panic like std does.

You could also have a toggle of some kind somewhere like Portable and Desktop then its up to the user to figure out which is better for their use case given a list of features each one supports.

Also as far as wgpu stability goes the bevy engine uses it and I haven't seen them having any major issues with it. Also wgpu does support GLSL shaders so you might not need to completely rewrite them.

NHodgesVFX avatar Apr 20 '22 19:04 NHodgesVFX

btw, I'm not asking three-d to support compute shaders. three-d can stay simple (as it is right now), and only expose the current high/mid API abstracting over wgpu / openGL. but i would like to take that low level context rendering api to use compute shaders or other features based on my target hardware.

One reason I'm afraid of openGL is the driver issues and unsafety.

  1. windows GL drivers (especially intel / AMD) are much worse compared to vulkan / direct3D. I actually rewrote my project from glow to wgpu after i saw that my performance dropped 20%+ between linux and windows using openGL. but consistent with wgpu (vulkan). apple is also ofcourse, not going to support GL on its
  2. opengl error messages suck. you just get some number most of the time and that is IF you get a error message. if my app seg faults because of buffer overflow when i accidentally give the wrong vertex count to draw call, it will take me forever to debug it with no error messages. but with wgpu, it will simply panic with a clear message (which will be in logs ofc) and users can just post the logs on github issues. a much better experience compared to sitting hours in front of renderdoc and hoping that i can reproduce it.

one really really convincing argument for three-d itself, regardless of my niche use case, is that wgpu is getting angle backend which allows it to run even on gles 2 or dx11 platforms (source: wgpu README).

if i use three-d (with wgpu) and find that some of my users using windows 11 have issues with vulkan drivers, i could just change a single line in my app and release a dx12 version until the drivers are fixed as a workaround or even gles with less performance workarounds. I can even just change the backend i use at program startup based on user configuration (MYAPP_DRIVER_BACKEND) and ask them to test if some bug is happening with other backends too. its way too convenient :)

I cannot use sprites for now. I'm making a overlay application, which just shows stuff "over" the game (Guild Wars 2) with a transparent window with mouse passthrough. so, i must keep my resource usage as low as possible to not compete with the game itself. very very niche case :D and i also don't want to lose in performance benchmarks with other competing similar non-rust Overlays.

coderedart avatar Apr 20 '22 21:04 coderedart

I think both of you have valid points πŸ‘

This is of course not just a discussion about compute shaders, but I think it is a good example of a feature that could be added at some point in the future to three-d and hopefully it's possible to disable the feature compile time on the platforms where it is not supported (I already do that with a few features). However, as noted, newer OpenGL versions also supports compute shaders, so you could take advantage of the possibility to combine low-level graphics calls with high-level three-d features and basically do the compute shader part "manually" using OpenGL and three-d for the rest. That means compute shaders are already supported, though not really in a nice way and maybe not on all platforms which was possible if using another backend.

That leads os to the points about OpenGL unsafety and so on, which are very valid indeed. One of the points of using a library like three-d is of course to avoid all of the problems that OpenGL (or other graphics APIs) can cause. However, if you combine three-d features with direct OpenGL calls, then you still have to fight with OpenGL errors in the low-level part of the code. I'm not sure how much better I think other graphics API's are, but if using WGPU then it sounds like it's would be a better experience.

Driver bugs is also a valid point, I'm don't have a windows computer, so I don't know how bad it is. And yeah apple support is also a valid point as I also said earlier. However, these things tend to move very slowly (I predict that WebGPU is not supported on all major browsers before at least 5 years, and probably 10 πŸ˜† ).

WGPU sounds really fantastic from a developer point of view, but as someone that has been hoping for some universal graphics API for ages, I reserve the right to be a bit sceptical πŸ˜„ I'm mostly concerned that there are some differences between the API's that cannot be properly aligned, but as three-d should be simple and therefore use standard drawing features of the graphics API, that might not be a problem. Anyway, I think it's definitely worth the try. If anyone wants to make a WGPU backend, please just write on this issue πŸ‘ Otherwise, I will look at it at some point.

And @coderedart, your use case sounds super nice, please share screenshots or something, if you'd like. And it might be super niche, but I think it is a quite typical that you want to use three-d for the "standard" drawing stuff and then make a custom low-level implementation for the very specific thing that makes your application unique. Maybe you can also consider using mid-level features in the core module, they should not introduce any overhead πŸ™‚

asny avatar Apr 24 '22 06:04 asny

@asny I will also add to discussion. WebGPU is new, it removed a lot of mistakes from previous graphics api interfaces. It provide easier interface and scalability than OpeGL, my boss which is senior OpenGL engineer is saying he never want to go back to OpenGL :D :D, But in future WebGPU will provide access to Vulkan/Metal/DirectX core via browser, so for us who develop Web3D content for industry it will be gamechanger and we can create bigger and better looking applications :)

And basically, when WebGPU will be supported across browsers, you can remove all your opengl code, there will be no backend, there will be only webgpu , which will cover opengl,vulkan,metal for your :)

erikpa1 avatar Jun 25 '22 14:06 erikpa1

@erikpa1 This is a discussion is about using WGPU, the Rust crate, not WebGPU the graphics API πŸ™‚

asny avatar Jun 26 '22 11:06 asny

@asny wgpu is rust crate which implements webgpu standard :) so I think thats the same,...

erikpa1 avatar Aug 03 '22 13:08 erikpa1

if i wanted to add wgpu backend to three-d, where would i start? start porting the shaders and mid-level api?

I just realized that three-d uses custom windowing code for web, is there a reason not to use winit?

coderedart avatar Aug 08 '22 15:08 coderedart

if i wanted to add wgpu backend to three-d, where would i start? start porting the shaders and mid-level api?

That's a good question. This may be obvious but it should just be to change the context in the context module from glow to wgpu (switch between the two with a feature flag?) and use wgpu everywhere that currently use glow low-level functionality (again switch with the same feature flag) which primarily is in the core module. It seems like wgpu supports glsl shaders (with the glsl feature flag enabled), so no need to port the shaders yet.

This was the very naive description of the task, in practice it is probably not that easy to switch since glow and wgpu functionality is not equal. However, to figure out the problems exactly, one just have to try it out, I think. So aiming at getting the triangle example running would be a good start. In the process, when you encounter problems that has no obvious solution, let me know, and we can maybe figure it out together πŸ™‚ I'll try to be quick to respond 🀞 How does that sound?

I just realized that three-d uses custom windowing code for web, is there a reason not to use winit?

Well, I'm pretty sure winit didn't support web when I started using it (at least I found out recently that it had), so that is the reason. So I guess that is a task as well, to replace the canvas code with winit πŸ™‚

asny avatar Aug 08 '22 19:08 asny

understood, i will start by first porting to winit, which is useful regardless of the wgpu stuff.

not urgent, but one thing that will need consideration for high level APIs is that wgpu can be multi-threaded, so for example, you could setup a rendergraph first and execute it later in a background thread like pipelined rendering.

coderedart avatar Aug 08 '22 20:08 coderedart

Sounds great πŸ‘

Good point. For the record, I think we should avoid multi threading right now to not complicate things further, but I guess that is also what you are saying. However, I guess the solution is also relevant with respect to the immediate mode of OpenGL and command queue of wgpu. I guess we need to accumulate the commands in a command queue for wgpu and then apply it when we render? Or maybe at the end of the frame? Right now, uniforms, buffers, textures etc are updated right away when something change.

asny avatar Aug 09 '22 12:08 asny

porting to winit was pretty easy.

but I give up on adding wgpu to three-d. It is very much possible to do so, but first, rewriting it from scratch seems to be much simpler and easier than patching the existing code. and second, i also don't have enough rendering knowledge to pull it off.

  1. the hardest part is probably shader reflection. need to use naga to reflect compiled shaders and replace the existing Program object with a PipeLine object. naga event provides a proper way to add defines . Though, i am honestly afraid of touching this as my shader skills are garbage (I have no idea about how bindings groups / locations are assigned to uniforms and attributes if they are not provided in layout explicitly. ).
  2. As i started refactoring, i had the feeling multiple times that the abstractions for opengl don't seem to be as promising for wgpu. Ofcourse, we could rewrite them, but then it wouldn't be three-d anymore.. and a completely different library. and we don't know where the rewrites will stop either or that they will be actually good.
  3. Finally, i don't think patching this crate instead of rewriting is worth the effort. this will definitely take a few days of work to complete. during that time, we can probably have a new crate from scratch with much cleaner API and less effort.

Ofcourse, if someone else feels different, then they are welcome to try. that's why i mentioned naga and shader reflection so that the next person knows where to start.

coderedart avatar Aug 10 '22 05:08 coderedart

but I give up on adding wgpu to three-d. It is very much possible to do so, but first, rewriting it from scratch seems to be much simpler and easier than patching the existing code. and second, i also don't have enough rendering knowledge to pull it off.

I totally understand, I tried to warn you that this was no small endeavour πŸ˜† I'm not sure I agree about rewriting from scratch now that I know how much effort that takes, but you are right that three-d was specifically designed with OpenGL/WebGL in mind. That said, the core rendering concepts (Buffer, Texture, program aka RenderPipeline) are the same no matter the graphics API and since three-d aim for doing the standard rendering easy (and not the 10% special cases) three-d would use very limited subset of wgpu and make no attempt to support anything fancy (but still make it possible to do yourself, giving access to the low-level context). Therefore, it should be doable to add support for wgpu without having to do a lot of major changes to the API. However, it might be needed to do some workarounds especially since OpenGL/WebGL and wgpu behaves fundamentally differently with respect to sending commands to the GPU. But again, I think it is doable but requires a lot of effort.

About the shaders, if it is not easy to do automatic conversion using Naga (I would just do it offline and have both copies of the shader in the source) they could be written again. Shouldn't be a big problem to do, it again just requires effort, and of course multiple shaders needs to be kept in sync.

Finally, i don't think patching this crate instead of rewriting is worth the effort. this will definitely take a few days of work to complete. during that time, we can probably have a new crate from scratch with much cleaner API and less effort.

I'll dare you to do it πŸ˜†

asny avatar Aug 10 '22 18:08 asny

Based on the above conversation I wonder if their would be a reason to keep Glow and not just have wgpu as the only backend. Wgpu supports opengl es, webgl2 and angle which should cover older computers and web(until webgpu is prevalent).

NHodgesVFX avatar Aug 10 '22 19:08 NHodgesVFX

Yeah that might be a good approach but i would prefer that both live alongside each other in the beginning if it's at all possible. Again the overall structure of three-d should stay the same since the concepts are the same so should be doable to switch between the two contexts. The main advantage to only use wgpu as I see it is that we don't have to duplicate shaders, which is also a significant advantage πŸ™‚ and of course I might also be wrong in my analysis πŸ˜„ I want to give it a go at some point but I also really like to do something fun as the next task so I'm not sure when that will be.

asny avatar Aug 11 '22 06:08 asny

Based on the above conversation I wonder if their would be a reason to keep Glow and not just have wgpu as the only backend. Wgpu supports opengl es, webgl2 and angle which should cover older computers and web(until webgpu is prevalent).

One reason is because wgpu currently has issues with hybrid graphics on Linux. Particularly if the dpgu is Nvidia based, and it seems related to wayland (xorg is unmaintained tech now). If wgpu were to be used it would have to closely follow upstream. You can see some of what I've experienced here

flukejones avatar Aug 04 '23 08:08 flukejones