Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: webgl/stdweb backend #1900

Closed
Diggsey opened this issue Apr 1, 2018 · 27 comments
Closed

Feature: webgl/stdweb backend #1900

Diggsey opened this issue Apr 1, 2018 · 27 comments

Comments

@Diggsey
Copy link
Contributor

Diggsey commented Apr 1, 2018

Using https://docs.rs/webgl_stdweb/0.1.0/webgl_stdweb/struct.GLContext.html

I've tried a couple of times to integrate this, but it's very non-trivial: obviously I'd like to reuse as much as possible from the GL backend, but it was never designed to have a separation between the code which translates GFX concepts into GL concepts, and the code which actually interacts with the OpenGL API.

@chpio
Copy link

chpio commented Jul 2, 2018

is there a easy way to compile spirv_cross to wasm/include it in the build? also it would be really nice to run spriv_cross as a build step instead of including it into the build as a dependency.

@Diggsey
Copy link
Contributor Author

Diggsey commented Jul 2, 2018

I made some progress on this: I managed to create true C-like bindings to webgl by borrowing opengl.js from emscripten, running it through a custom-built preprocessor to handle the emscripten-specific macros and then incorporating that into a new stdweb-based gl-generator backend.

The net result is that I can call the normal OpenGL API on the wasm32-unknown-unknown target. Since then I've been working on extricating the dependency on winit from the gfx opengl backend.

@kvark
Copy link
Member

kvark commented Jul 3, 2018

@Diggsey u r da the best, man! Please keep up cracking this nut, we are excited to see this coming :)

@Boscop
Copy link

Boscop commented Aug 11, 2018

I'm also very interested in this, what's the current status of this? :)

@grovesNL
Copy link
Contributor

grovesNL commented Sep 7, 2018

@Diggsey is there a branch somewhere that contains your progress on this?

@cretz
Copy link

cretz commented Sep 26, 2018

As an alternative to stdweb, consider the recently announced web-sys crate, e.g. canvas.get_context("webgl").unwrap().dyn_into::<web_sys::WebGlRenderingContext>()

@aep
Copy link

aep commented Oct 13, 2018

whats missing here, anything we can help with?

@luckielordie
Copy link

Is anyone working on this?

@kvark
Copy link
Member

kvark commented Oct 19, 2018

Looks like we are back to square one here, with @Diggsey disappearing. At least we can consider web-sys without risking of losing any work ;)

@eira-fransham
Copy link

I'm working on a Processing-like framework in Rust and this would be amazing to allow me to have an online sketchpad similar to a combination of https://valentin.dasdeck.com/processing/ and the Rust playground.

@luckielordie
Copy link

I'm planning on giving this a go with web-sys. Obviously it's a matter of time for me. Any help people could give me understanding the HAL Interface would be a major help.

@kvark
Copy link
Member

kvark commented Nov 22, 2018

@luckielordie HAL interface is basically Vulkan, plus a bit of type sugar in a few places.

@luckielordie
Copy link

@luckielordie HAL interface is basically Vulkan, plus a bit of type sugar in a few places.

I'm going to need to brush up on my Vulkan then!

@luckielordie
Copy link

luckielordie commented Nov 23, 2018

A quick update, I've forked and created a branch here. If you want to contribute you're more than welcome to request access and I'll open it up. I'm fairly new to Rust so I'll always appreciate a more experienced eye.

@goddessfreya
Copy link
Contributor

@luckielordie Might be preferable for maintainability reasons if you directly integrate webgl support into the gl backend, instead of having to separate backends.

@mmacedoeu
Copy link

I have also started some proof of concept using stdweb. I choose stdweb for two reasons: it has a broader scope with more stuff included and it plans to migrate to web-sys on the future.

So far I come to this challenging problems: spirv-cross should move to build.rs stage, glutin should be replaced with winit or plain stdweb, threads and structure like Starc should be rethought to web-friendly maybe just like crate yew use webworkers for concurrency.

I also a brand new backend instead of using gl, it may be possible to merge both in the end and use a lot of conditional compile flags but so far I am trying to just make things work and optimize latter on.

@kvark
Copy link
Member

kvark commented Nov 26, 2018

I also a brand new backend instead of using gl, it may be possible to merge both in the end and use a lot of conditional compile flags but so far I am trying to just make things work and optimize latter on.

wow, that sounds like a world of pain, tbh

Btw, what do you mean by "spirv-cross should move to build.rs stage"?

@mmacedoeu
Copy link

mmacedoeu commented Nov 26, 2018

spirv-cross is a binding to native c/cpp lib so I think rustc will not be able to compite it to WASM, so you need to try to compile it (cross) using emsdk or just make all spirv to glsl transpile be done in build.rs pre-compilation stage so there is NO runtime translation done. Still I have not look into possible implications for this.

It really is a pain cave, any insights?

@grovesNL
Copy link
Contributor

I also a brand new backend instead of using gl, it may be possible to merge both in the end and use a lot of conditional compile flags but so far I am trying to just make things work and optimize latter on.

I don't think we should need a lot of conditional compile flags for the gl backend, could we just use feature flags (optionally with a macro)? The function signatures should almost be the exact same between OpenGL ES (which we need to support anyway) and WebGL.

spirv-cross is a binding to native c/cpp lib so I think rustc will not be able to compite it to WASM, so you need to try to compile it (cross) using emsdk or just make all spirv to glsl transpile be done in build.rs pre-compilation stage so there is NO runtime translation done.

We need to allow runtime translation of SPIR-V to GLSL with spirv_cross, so it's not possible to do it all in build.rs. I think compiling the wrapper in spirv_cross to wasm is fine to start with. I can help with this - the wrapper exists in spirv_cross.

@grovesNL
Copy link
Contributor

grovesNL commented Dec 26, 2018

I have an experimental branch rendering the quad example using WebGL2 and web-sys (through the wasm32-unknown-unknown target). I hardcoded the shader for now because I don't have SPIRV-Cross in wasm yet.

screen shot 2018-12-26 at 11 22 33 am

I'll put the branch somewhere soon if anyone's interested, but there a few other issues we need to work through:

  • We probably need to create some unified OpenGL/WebGL bindings for gfx (in a separate crate) to avoid use of #[cfg(target_arch = "wasm32")] etc. everywhere, and use a feature list to distinguish which functions are callable.
  • A wrapper for the web-sys WebGL bindings would be useful to be able to pass references etc. For example, currently it's a bit difficult to work with raw web_sys::WebGlProgram because we really want to be able to use this in multiple places but it's not Copy (unlike gl::types::GLuint used now).
  • As mentioned before we'll need to get the C++ SPIRV-Cross library (and the thin C wrapper in spirv_cross) to wasm through emscripten. Then we can build the Rust parts of spirv_cross to wasm32-unknown-unknown and call into the emscripten library.
  • We need a simple way to create an event loop outside of winit, the boilerplate in web-sys for this is a bit noisy so maybe there is a crate that does this already, or we create something simple.
  • Send and Sync bounds on the Backend trait are problematic right now for web-sys types mentioned above because they can't be shared with web workers. I simply disabled them in my experimental branch for the wasm32 target. But maybe there's a better way to deal with this for now. We could consider proxying calls from web workers to the main thread, but this is definitely not straightforward.
  • (longer term) It would be useful to look into how to manage async resource loading (shaders, textures, etc.) to take full advantage of the web, this should reduce the initial bundle size of the generated wasm making it faster to parse/compile on first load.

We can probably start to split these into issues and address them individually.

Edit: I posted the branch here for reference master...grovesNL:webgl-hacking It's prototype quality at the moment (breaks the regular gl backends because of the temporary logging code, only supports quad, unformatted, etc.) but should give us some ideas about how to properly support it through the points mentioned above.

@icefoxen
Copy link
Contributor

Awesome. I really don't have the time or energy to majorly contribute to this, but if it becomes a bit more mature I'll probably be trying to use it in ggez, which will probably result in lots of issues and hopefully attached fixes. :D

The event loop stuff is interesting, what do you need that winit doesn't provide? I was under the impression there was some pretty srs work in progress to make it possible to work more nicely on web already.

@grovesNL
Copy link
Contributor

Yeah I plan to keep working through these issues for a while. I’m currently looking into the feasibility of a thin abstraction to combine WebGL and OpenGL types/signatures with some helpers we’ll need.

I’m not sure of the situation with winit/wasm support but that would be the ideal solution when it’s ready. I scanned the issue tracker a few days ago and it seemed like it was still planned or early WIP so didn’t try it out. If it’s already supported then that would be great. If it’s not supported yet, we could just have a simple wrapper to simplify the boilerplate for now.

@grovesNL
Copy link
Contributor

A small update: I started investigating the first two points by creating abstractions over WebGL + OpenGL types/function signatures with primitive key types (which are Copy), and a simple render loop. My experiment is located at https://github.com/grovesNL/glow

There's an example in that repository that shows how the abstraction works at the moment. Also until we have something like winit on wasm to help with the event loop, events like key presses, resizing, etc. are still target-specific. Any feedback about this abstraction would be really helpful! If this experiment turns out to be useful then I should be able to quickly recreate my branch on top of it.

@icefoxen
Copy link
Contributor

Looks pretty reasonable to me, from what little I know of such things. My only question would be, can you use a trait object rather than an enum for dispatching on WebGl1 vs WebGl2? I guess that would basically be splitting your WebRenderingContext into WebRenderingContextGl1 and WebRenderingContextGl2 and impl'ing RenderingContext for both.

Making winit work on wasm is something that the winit people rather want, but it looks like a bit of a beast of a change to make it work well. See rust-windowing/winit#459 for the core issue, it seems.

@grovesNL
Copy link
Contributor

Yeah definitely. I’m hoping this enum will mostly disappear if we could get wasm bindgen to automatically create a base trait for any common signatures. Maybe I could use a simple macro to avoid some of the repetition for now.

@grovesNL
Copy link
Contributor

grovesNL commented Jan 4, 2019

I've made some more progress in #2554 if anyone wants to take a look.

bors bot added a commit that referenced this issue Jun 8, 2019
2554: Add wasm32-unknown-unknown/WebGL support r=kvark a=grovesNL

Start to make a more maintainable version of my old branch from #1900 (comment). Heavily WIP but maybe somebody wants to start giving some feedback as I work through the remainder of issues.

This PR replaces gl_generator with glow (https://github.com/grovesNL/glow), a experimental crate meant to unify WebGL/OpenGL types and function signatures. Currently unsupported functions will just panic, but I think it makes sense to move some of the version logic and extension fallbacks in there too (removing them from the gl backend). The WebGL types are now just keys (and `Copy`) which fixes some of the issues I mentioned previously.

This is for the wasm32-unknown-unknown target and uses web-sys.

TODO:
- [X] ~~(major) spirv_cross wrapper on wasm32-unknown-unknown and C++ library through emscripten. For now the quad shaders are hardcoded.~~ See grovesNL/spirv_cross#92. (I'll probably leave the PR open until we work out how the integration between wasm bundles should work)
- [X] ~~Consolidate render loop somehow (see WIP in glow example https://github.com/grovesNL/glow/blob/master/examples/hello/src/main.rs#L118). I need some more ideas on how to work around the `'static` bounds for wasm32 here. The basic idea is that wasm32 has to use callbacks and we use spinloops on the native target, so we would ideally like to unify these (at least for use in examples but also simple applications). For wasm32 with the quad example I just render once and quit instead.~~ Currently winit is working through the implementation of "Event Loop 2.0" and there's been [some effort to write a stdweb backend for this](rust-windowing/winit#797), which we could later help port to wasm32-unknown-unknown. I think for now we can just keep the wasm render loop path separate in gfx examples, and things will work naturally once winit wasm32-unknown-unknown support is ready.
- [X] ~~Remove all remaining `#[cfg(not(target_arch = "wasm32"))]` wherever possible to make this more maintainable.~~ There are a few places remaining that can be removed when we move some logic into glow, like version parsing and extension checking. Some other parts like the runloop can't be addressed without winit support for wasm32-unknown-unknown or other workarounds in quad.
- [X] ~~Decide where to put things like `index.html` for examples (I've excluded it for now) and guide about how to create wasm bundle with wasm-bindgen.~~
- [X] ~~Consider how logging should work – I don't see how to redirect stdout to `console.log` so it's a bit manually at the moment. It would be really cool if things like `info!` just work automatically with wasm32-unknown-unknown.~~ We should be able to use https://github.com/iamcodemaker/console_log for the wasm backend without any major challenges.
- [X] ~~Publish glow~~ Published 0.2.0
- [x] ~~Publish updated spirv_cross~~ Published 0.14.0
- [X] ~~Add wasm-bindgen to CI~~ This has been added

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/gfx-rs/gfx/2554)
<!-- Reviewable:end -->


Co-authored-by: Joshua Groves <josh@joshgroves.com>
@erlend-sh
Copy link

Resolved by #2554?

@kvark kvark closed this as completed Jun 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests