mrk-its / bevy_webgl2

WebGL2 renderer plugin for Bevy game engine
MIT License
172 stars 46 forks source link

Shader compilation panics #21

Closed zaszi closed 3 years ago

zaszi commented 3 years ago

First of all, a major thanks for making this software! With bevy_webgl2, I can now run my (still relavely simple) 2D game in the browser.

Sadly, this only worked fine when I was simply drawing geometric squares on a window. Since I actually went beyond drawing simple squares and started loading a tilemap and spawning a small dungeon, I got the following error in my browser at runtime:

hiveworld.js:359 panicked at 'called `Result::unwrap()` on an `Err` value: "ERROR: 0:1: \'\n\' : invalid version directive\nERROR: 0:5: \'layout\' : syntax error\n\u{0}"', /home/zaszi/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_webgl2-0.4.2/src/renderer/webgl2_render_resource_context.rs:74:81

When digging into what this is actually referring to, it seems my project specifically breaks on shader compilation within bevy_webgl2:

match &shader.source {
            ShaderSource::Glsl(source) => {
                info!("compiling shader: {:?}", source);
                compile_shader(&self.device.get_context(), shader_type, source).unwrap()
            }
            _ => {
                panic!("unsupported shader format");
            }
        }

Here are the relevant bits of my Cargo.toml (note: conditional dependency features are a nightly-only feature gated behind the -Zfeatures=itarget flag and won't work on stable). Additionally, the game runs perfectly fine natively on Linux.

[lib]
crate-type = ["cdylib", "rlib"]

[features]
default = []

[dependencies]
wasm-bindgen = "0.2"
# bevy_tilemap = "0.3"
bevy_tilemap = { git = "https://github.com/joshuajbouw/bevy_tilemap.git", rev = "a0d26fc" }
oorandom = "11.1"

[dev-dependencies]
wasm-bindgen-test = "0.2"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
bevy = {version = "0.4", default-features = false, features = ["bevy_dynamic_plugin", "bevy_wgpu", "bevy_winit", "png", "render", "x11", "wayland"]}
getrandom = "0.2"

[target.'cfg(target_arch = "wasm32")'.dependencies]
bevy = {version = "0.4", default-features = false, features = ["bevy_winit", "png", "render"]}
bevy_webgl2 = "0.4"
console_error_panic_hook = "0.1"
getrandom = { version = "0.1", features = ["wasm-bindgen"] }
wee_alloc = "0.4"

[profile.release]
lto = true
panic = "abort"

Browser: Qutebrowser, but happens on Firefox and likely others too. Rustc: 1.51.0-nightly (a62a76047 2021-01-13) Distribution: wasm-pack, I manually host the wasm, js and asset files.

I'm at a bit of a loss as where to continue troubleshooting this. I'm not doing anything unique or special with Bevy (yet) that isn't common in examples, besides the usage of bevy_tilemap (which should work on WASM). Perhaps someone can point me in the right direction here?

willcrichton commented 3 years ago

Can you post your shader? It needs to start with #version 300 es, not #version 450.

zaszi commented 3 years ago

All right, after some more digging I figured out that bevy_tilemap does indeed include shaders, which are all #version 450. If I manually edit them to #version 300 es, compilation fails complaining about ES shaders for SPIR-V requiring version 310 or higher.

What would the right course of action be here? Should bevy_webgl2 support these or should bevy_tilemap downgrade shader versions? Or is there some other way to have these two plugins play nice together?

joshuajbouw commented 3 years ago

Unless I'm mistakened, all of Bevy's are version 450 too unless there are magic 350 es shaders somewhere that isn't obvious where?

willcrichton commented 3 years ago

As far as I can tell, that's correct. bevy_webgl2 replaces all of Bevy's built-in shaders, as you can find in this directory: https://github.com/mrk-its/bevy_webgl2/tree/master/src/shaders

I'm assuming this is because WebGL's support for GLSL is more limited than native? But @mrk-its is the best person to confirm.

joshuajbouw commented 3 years ago

Oh totally missed that. That is a good question. I'll throw out some options.

I think the 2nd option is better, then it at least is quite inline with what is going on right now i.e webgl providing the alternative shaders. I wouldn't mind making a PR for that though to save you the effort.

mrk-its commented 3 years ago

Hey, sorry for late reply. @willcrichton bevy_webgl2 has to use 300ES shaders because this is the only version supported by webgl2.

@joshuajbouw Regarding adding support for bevy_tilemap (or other libraries) - definitely 1st option is better. It is the only approach allowing for having these shaders up to date in all third party libraries that want to be used with bevy_webgl2 (keeping bevy_webgl2 in sync with bevy itself is a challenge).

I took a look on your shaders and it seems porting to 300ES should be straightforward. Simply compare side by side bevy and bevy_webgl2 versions and you easily notice differences. For example uniform layout declarations are different (in bevy_webgl2 are in comments), there is no buffer type (in bevy_webgl2 I'm using array with constant size), some internal variables have different names (for example gl_VertexIndex vs gl_VertexID). Some time ago I even wrote some preprocessing macros covering these differences, so it was possible to write single version of shaders for both targets (simply prepending source with macro definitons for 300ES or 450 versions). bevy_webgl2 also automatically prepends #define WEBGL on top of shaders, so all differences may be applied in shaders themselves with #ifdef preprocessor directives (except #version directive - it must be in first line and cannot be changed by conditional compilation)

zaszi commented 3 years ago

All right, it's clear that this is not a bevy_webgl2 issue and therefore I'll close this. Perhaps in the future bevy_tilemap can support these shaders so these two plugins can play nicely together. For now, I'll override the shaders in my project. Thanks, everyone!