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

Implement WebGL2 Backend #1686

Merged
merged 4 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ jobs:
run: |
cargo clippy --target ${{ matrix.target }} -p wgpu

# Build for WebGL
cargo clippy --target ${{ matrix.target }} -p wgpu --features webgl -- -D warnings

# build docs
cargo doc --target ${{ matrix.target }} -p wgpu --no-deps

Expand Down
34 changes: 34 additions & 0 deletions run-wasm-example.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/env bash

set -e

echo "Compiling..."
cargo build --example $1 --target wasm32-unknown-unknown --features webgl

echo "Generating bindings..."
mkdir -p target/wasm-examples/$1
wasm-bindgen --target web --out-dir target/wasm-examples/$1 target/wasm32-unknown-unknown/debug/examples/$1.wasm
cp wasm-resources/index.template.html target/wasm-examples/$1/index.html
sed -i "s/{{example}}/$1/g" target/wasm-examples/$1/index.html

# Find a serving tool to host the example
SERVE_CMD=""
SERVE_ARGS=""
if which basic-http-server; then
SERVE_CMD="basic-http-server"
SERVE_ARGS="target/wasm-examples/$1 -a 127.0.0.1:1234"
elif which miniserve && python3 -m http.server --help > /dev/null; then
SERVE_CMD="miniserve"
SERVE_ARGS="target/wasm-examples/$1 -p 1234 --index index.html"
elif python3 -m http.server --help > /dev/null; then
SERVE_CMD="python3"
SERVE_ARGS="-m http.server --directory target/wasm-examples/$1 1234"
fi

# Exit if we couldn't find a tool to serve the example with
if [ "$SERVE_CMD" = "" ]; then
echo "Couldn't find a utility to use to serve the example web page. You can serve the `target/wasm-examples/$1` folder yourself using any simple static http file server."
fi

echo "Serving example with $SERVE_CMD at http://localhost:1234"
$SERVE_CMD $SERVE_ARGS
3 changes: 3 additions & 0 deletions wasm-resources/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# WASM Resources

This directory contains resources used when building the WGPU examples for web.
14 changes: 14 additions & 0 deletions wasm-resources/index.template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<script type="module">
import init from "./{{example}}.js";
window.addEventListener("load", () => {
init();
});
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions wgpu-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ path = "../wgpu-hal"
package = "wgpu-hal"
version = "0.10.1"

[target.'cfg(target_arch = "wasm32")'.dependencies]
hal = { path = "../wgpu-hal", package = "wgpu-hal", version = "0.10", features = ["gles"] }
cwfitzgerald marked this conversation as resolved.
Show resolved Hide resolved

[target.'cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))'.dependencies]
hal = { path = "../wgpu-hal", package = "wgpu-hal", version = "0.10", features = ["metal"] }
#Note: could also enable "vulkan" for Vulkan Portability
Expand Down
7 changes: 6 additions & 1 deletion wgpu-core/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ fn main() {
metal: { all(not(wasm), apple) },
dx12: { all(not(wasm), windows) },
dx11: { all(false, not(wasm), windows) },
gl: { all(not(wasm), unix_wo_apple) },
gl: {
any(
all(not(wasm), unix_wo_apple),
wasm
)
},
}
}
4 changes: 4 additions & 0 deletions wgpu-core/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4547,6 +4547,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
{
self.poll_devices::<hal::api::Dx11>(force_wait, &mut closures)?;
}
#[cfg(gl)]
{
self.poll_devices::<hal::api::Gles>(force_wait, &mut closures)?;
}

unsafe {
closures.fire();
Expand Down
1 change: 1 addition & 0 deletions wgpu-core/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,7 @@ impl HalApi for hal::api::Dx11 {
impl HalApi for hal::api::Gles {
const VARIANT: Backend = Backend::Gl;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
#[allow(clippy::needless_update)]
Instance {
name: name.to_owned(),
gl: Some(hal_instance),
Expand Down
7 changes: 5 additions & 2 deletions wgpu-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub mod resource;
mod track;
mod validation;

pub use hal::api;
pub use hal::{api, MAX_BIND_GROUPS, MAX_COLOR_TARGETS, MAX_VERTEX_BUFFERS};

use atomic::{AtomicUsize, Ordering};

Expand Down Expand Up @@ -211,7 +211,10 @@ macro_rules! gfx_select {
wgt::Backend::Dx12 => $global.$method::<$crate::api::Dx12>( $($param),* ),
//#[cfg(all(not(target_arch = "wasm32"), windows))]
//wgt::Backend::Dx11 => $global.$method::<$crate::api::Dx11>( $($param),* ),
#[cfg(all(not(target_arch = "wasm32"), unix, not(any(target_os = "ios", target_os = "macos"))))]
#[cfg(any(
all(unix, not(target_os = "macos"), not(target_os = "ios")),
target_arch = "wasm32"
))]
wgt::Backend::Gl => $global.$method::<$crate::api::Gles>( $($param),+ ),
other => panic!("Unexpected backend {:?}", other),

Expand Down
5 changes: 5 additions & 0 deletions wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ mtl = { package = "metal", version = "0.23.1" }
objc = "0.2.5"
core-graphics-types = "0.1"

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { version = "0.2" }
web-sys = { version = "0.3", features = ["Window", "HtmlCanvasElement", "WebGl2RenderingContext"] }
js-sys = { version = "0.3" }

[dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "52d74e9"
Expand Down
38 changes: 34 additions & 4 deletions wgpu-hal/src/gles/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ impl super::Adapter {

let shading_language_version = {
let sl_version = gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION);
log::info!("SL version: {}", sl_version);
log::info!("SL version: {}", &sl_version);
let (sl_major, sl_minor) = Self::parse_version(&sl_version).ok()?;
let value = sl_major as u16 * 100 + sl_minor as u16 * 10;
naga::back::glsl::Version::Embedded(value)
Expand All @@ -209,9 +209,11 @@ impl super::Adapter {
let max_storage_block_size =
gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE) as u32;

// WORKAROUND:
// In order to work around an issue with GL on RPI4 and similar, we ignore a zero vertex ssbo count if there are vertex sstos. (more info: https://github.com/gfx-rs/wgpu/pull/1607#issuecomment-874938961)
// The hardware does not want us to write to these SSBOs, but GLES cannot express that. We detect this case and disable writing to SSBOs.
// WORKAROUND: In order to work around an issue with GL on RPI4 and similar, we ignore a
// zero vertex ssbo count if there are vertex sstos. (more info:
// https://github.com/gfx-rs/wgpu/pull/1607#issuecomment-874938961) The hardware does not
// want us to write to these SSBOs, but GLES cannot express that. We detect this case and
// disable writing to SSBOs.
let vertex_ssbo_false_zero =
vertex_shader_storage_blocks == 0 && vertex_shader_storage_textures != 0;
if vertex_ssbo_false_zero {
Expand Down Expand Up @@ -254,6 +256,7 @@ impl super::Adapter {
&& max_storage_block_size != 0
&& (vertex_shader_storage_blocks != 0 || vertex_ssbo_false_zero),
);
downlevel_flags.set(wgt::DownlevelFlags::FRAGMENT_STORAGE, ver >= (3, 1));

let mut features = wgt::Features::empty()
| wgt::Features::TEXTURE_COMPRESSION_ETC2
Expand Down Expand Up @@ -283,6 +286,14 @@ impl super::Adapter {
super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT,
ver >= (3, 1),
);
private_caps.set(
super::PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE,
cfg!(not(target_arch = "wasm32")),
);
private_caps.set(
super::PrivateCapabilities::CAN_DISABLE_DRAW_BUFFER,
cfg!(not(target_arch = "wasm32")),
);

let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32;
let max_texture_3d_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) as u32;
Expand Down Expand Up @@ -340,6 +351,12 @@ impl super::Adapter {
};

let mut workarounds = super::Workarounds::empty();

workarounds.set(
super::Workarounds::EMULATE_BUFFER_MAP,
cfg!(target_arch = "wasm32"),
);

let r = renderer.to_lowercase();
// Check for Mesa sRGB clear bug. See
// [`super::PrivateCapabilities::MESA_I915_SRGB_SHADER_CLEAR`].
Expand All @@ -358,13 +375,17 @@ impl super::Adapter {
let downlevel_defaults = wgt::DownlevelLimits {};

// Drop the GL guard so we can move the context into AdapterShared
// ( on WASM the gl handle is just a ref so we tell clippy to allow
// dropping the ref )
#[allow(clippy::drop_ref)]
drop(gl);

Some(crate::ExposedAdapter {
adapter: super::Adapter {
shared: Arc::new(super::AdapterShared {
context,
private_caps,
downlevel_flags,
workarounds,
shading_language_version,
}),
Expand Down Expand Up @@ -461,6 +482,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
zero_buffer,
temp_query_results: Vec::new(),
draw_buffer_count: 1,
current_index_buffer: None,
},
})
}
Expand Down Expand Up @@ -560,11 +582,13 @@ impl crate::Adapter<super::Api> for super::Adapter {
formats: if surface.enable_srgb {
vec![
wgt::TextureFormat::Rgba8UnormSrgb,
#[cfg(not(target_arch = "wasm32"))]
wgt::TextureFormat::Bgra8UnormSrgb,
]
} else {
vec![
wgt::TextureFormat::Rgba8Unorm,
#[cfg(not(target_arch = "wasm32"))]
wgt::TextureFormat::Bgra8Unorm,
]
},
Expand All @@ -589,6 +613,12 @@ impl crate::Adapter<super::Api> for super::Adapter {
}
}

// SAFE: WASM doesn't have threads
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for super::Adapter {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for super::Adapter {}

#[cfg(test)]
mod tests {
use super::super::Adapter;
Expand Down
11 changes: 7 additions & 4 deletions wgpu-hal/src/gles/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,17 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
) where
T: Iterator<Item = crate::BufferCopy>,
{
//TODO: preserve `src.target` and `dst.target`
// at least for the buffers that require it.
let (src_target, dst_target) = if src.target == dst.target {
(glow::COPY_READ_BUFFER, glow::COPY_WRITE_BUFFER)
} else {
(src.target, dst.target)
};
for copy in regions {
self.cmd_buffer.commands.push(C::CopyBufferToBuffer {
src: src.raw,
src_target: glow::COPY_READ_BUFFER,
src_target,
dst: dst.raw,
dst_target: glow::COPY_WRITE_BUFFER,
dst_target,
copy,
})
}
Expand Down
Loading