diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 69802293146..23cb3c2e98b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -77,6 +77,13 @@ jobs:
target: wasm32-unknown-unknown
kind: webgl
+ # Emscripten WebGL
+ - name: WebAssembly emscripten
+ os: ubuntu-20.04
+ channel: stable
+ target: wasm32-unknown-emscripten
+ kind: compile
+
name: Check ${{ matrix.name }}
runs-on: ${{ matrix.os }}
diff --git a/Cargo.lock b/Cargo.lock
index de656cabee0..c20a05146ad 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -601,8 +601,7 @@ dependencies = [
[[package]]
name = "glow"
version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f04649123493bc2483cbef4daddb45d40bbdae5adb221a63a23efdb0cc99520"
+source = "git+https://github.com/caiiiycuk/glow?rev=5abe786#5abe786973f0ccc2a8c37a44e360dc9f7ca73e43"
dependencies = [
"js-sys",
"slotmap",
@@ -743,6 +742,7 @@ checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"
dependencies = [
"libc",
"libloading",
+ "pkg-config",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index f11e2f43826..c9660902bc2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,7 +24,7 @@ default-members = ["wgpu", "wgpu-hal", "wgpu-info"]
[patch."https://github.com/zakarumych/gpu-alloc"]
#gpu-alloc = { path = "../gpu-alloc/gpu-alloc" }
-[patch."https://github.com/grovesNL/glow"]
+[patch."https://github.com/caiiiycuk/glow"]
#glow = { path = "../glow" }
[patch.crates-io]
diff --git a/run-wasm-emscripten-example.sh b/run-wasm-emscripten-example.sh
new file mode 100755
index 00000000000..0ed99a09d76
--- /dev/null
+++ b/run-wasm-emscripten-example.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+set -e
+
+set -- hello-triangle
+echo "Compiling..."
+EMMAKEN_CFLAGS="-g -s ERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry -s FULL_ES3=1" cargo build --example $1 --target wasm32-unknown-emscripten
+
+mkdir -p target/wasm-examples/$1/
+cp target/wasm32-unknown-emscripten/debug/examples/* target/wasm-examples/$1
+cat wasm-resources/index.em.template.html | sed "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
diff --git a/wasm-resources/index.em.template.html b/wasm-resources/index.em.template.html
new file mode 100644
index 00000000000..216b8d7c942
--- /dev/null
+++ b/wasm-resources/index.em.template.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml
index 359a9a108e0..03afe5b7610 100644
--- a/wgpu-hal/Cargo.toml
+++ b/wgpu-hal/Cargo.toml
@@ -43,7 +43,9 @@ gpu-descriptor = { version = "0.2", optional = true }
inplace_it = { version ="0.3.3", optional = true }
# backend: Gles
-glow = { version = "0.11", optional = true }
+# TODO: remove caiiiycuk/glow when
+# https://github.com/grovesNL/glow/pull/195 will be merged
+glow = { git = "https://github.com/caiiiycuk/glow", rev = "5abe786", optional = true }
# backend: Dx12
bit-set = { version = "0.5", optional = true }
@@ -59,6 +61,10 @@ egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], option
#Note: it's only unused on Apple platforms
libloading = { version = "0.7", optional = true }
+[target.'cfg(target_os = "emscripten")'.dependencies]
+egl = { package = "khronos-egl", version = "4.1", features = ["static", "no-pkg-config"], optional = true }
+libloading = { version = "0.7", optional = true }
+
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser"] }
native = { package = "d3d12", version = "0.4.1", features = ["libloading"], optional = true }
@@ -68,7 +74,7 @@ mtl = { package = "metal", version = "0.23.1" }
objc = "0.2.5"
core-graphics-types = "0.1"
-[target.'cfg(target_arch = "wasm32")'.dependencies]
+[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
wasm-bindgen = { version = "0.2" }
web-sys = { version = "0.3", features = ["Window", "HtmlCanvasElement", "WebGl2RenderingContext"] }
js-sys = { version = "0.3" }
@@ -86,4 +92,6 @@ features = ["wgsl-in"]
[dev-dependencies]
env_logger = "0.8"
+
+[target.'cfg(not(target_os = "emscripten"))'.dev-dependencies]
winit = "0.26"
diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs
index 722041048a9..8003246ad1f 100644
--- a/wgpu-hal/src/gles/device.rs
+++ b/wgpu-hal/src/gles/device.rs
@@ -1096,6 +1096,8 @@ impl crate::Device for super::Device {
#[cfg_attr(target_arch = "wasm32", allow(clippy::needless_borrow))]
Ok(fence.get_latest(&self.shared.context.lock()))
}
+
+ #[cfg_attr(target_os = "emscripten", allow(unreachable_code, unused_variables))]
unsafe fn wait(
&self,
fence: &super::Fence,
@@ -1114,6 +1116,12 @@ impl crate::Device for super::Device {
.iter()
.find(|&&(value, _)| value >= wait_value)
.unwrap();
+
+ // for some reason signature of glow's client_wait_sync didn't match to emscripten's client_wait_sync
+ // however it should be noop in emscripten
+ #[cfg(target_os = "emscripten")]
+ return Ok(true);
+
match gl.client_wait_sync(sync, glow::SYNC_FLUSH_COMMANDS_BIT, timeout_ns as i32) {
// for some reason firefox returns WAIT_FAILED, to investigate
#[cfg(target_arch = "wasm32")]
diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs
index 96bf0d81a31..01b610033f6 100644
--- a/wgpu-hal/src/gles/egl.rs
+++ b/wgpu-hal/src/gles/egl.rs
@@ -10,7 +10,9 @@ const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
const EGL_CONTEXT_FLAGS_KHR: i32 = 0x30FC;
const EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR: i32 = 0x0001;
const EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: i32 = 0x30BF;
+#[cfg_attr(target_os = "emscripten", allow(dead_code))]
const EGL_PLATFORM_WAYLAND_KHR: u32 = 0x31D8;
+#[cfg_attr(target_os = "emscripten", allow(dead_code))]
const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
const EGL_GL_COLORSPACE_KHR: u32 = 0x309D;
const EGL_GL_COLORSPACE_SRGB_KHR: u32 = 0x3089;
@@ -23,12 +25,20 @@ type WlDisplayConnectFun =
type WlDisplayDisconnectFun = unsafe extern "system" fn(display: *const raw::c_void);
+#[cfg(not(target_os = "emscripten"))]
+type EglInstance = egl::DynamicInstance;
+
+#[cfg(target_os = "emscripten")]
+type EglInstance = egl::Instance;
+
+#[cfg_attr(target_os = "emscripten", allow(dead_code))]
type WlEglWindowCreateFun = unsafe extern "system" fn(
surface: *const raw::c_void,
width: raw::c_int,
height: raw::c_int,
) -> *mut raw::c_void;
+#[cfg_attr(target_os = "emscripten", allow(dead_code))]
type WlEglWindowResizeFun = unsafe extern "system" fn(
window: *const raw::c_void,
width: raw::c_int,
@@ -141,7 +151,7 @@ enum SrgbFrameBufferKind {
/// Choose GLES framebuffer configuration.
fn choose_config(
- egl: &egl::DynamicInstance,
+ egl: &EglInstance,
display: egl::Display,
srgb_kind: SrgbFrameBufferKind,
) -> Result<(egl::Config, bool), crate::InstanceError> {
@@ -249,7 +259,7 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m
/// exclusive access when shared with multiple threads.
pub struct AdapterContext {
glow_context: Mutex,
- egl: Arc>,
+ egl: Arc,
egl_display: egl::Display,
pub(super) egl_context: egl::Context,
egl_pbuffer: Option,
@@ -261,7 +271,7 @@ unsafe impl Send for AdapterContext {}
/// A guard containing a lock to an [`AdapterContext`]
pub struct AdapterContextLock<'a> {
glow_context: MutexGuard<'a, glow::Context>,
- egl: &'a Arc>,
+ egl: &'a Arc,
egl_display: egl::Display,
}
@@ -331,7 +341,7 @@ impl AdapterContext {
#[derive(Debug)]
struct Inner {
- egl: Arc>,
+ egl: Arc,
#[allow(unused)]
version: (i32, i32),
supports_native_window: bool,
@@ -341,6 +351,7 @@ struct Inner {
/// Dummy pbuffer (1x1).
/// Required for `eglMakeCurrent` on platforms that doesn't supports `EGL_KHR_surfaceless_context`.
pbuffer: Option,
+ #[cfg_attr(target_os = "emscripten", allow(dead_code))]
wl_display: Option<*mut raw::c_void>,
/// Method by which the framebuffer should support srgb
srgb_kind: SrgbFrameBufferKind,
@@ -349,7 +360,7 @@ struct Inner {
impl Inner {
fn create(
flags: crate::InstanceFlags,
- egl: Arc>,
+ egl: Arc,
display: egl::Display,
) -> Result {
let version = egl.initialize(display).map_err(|_| crate::InstanceError)?;
@@ -443,8 +454,12 @@ impl Inner {
}
};
+ #[cfg(target_os = "emscripten")]
+ let pbuffer = None;
+
// Testing if context can be binded without surface
// and creating dummy pbuffer surface if not.
+ #[cfg(not(target_os = "emscripten"))]
let pbuffer =
if version >= (1, 5) || display_extensions.contains("EGL_KHR_surfaceless_context") {
log::info!("\tEGL context: +surfaceless");
@@ -494,7 +509,12 @@ unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}
impl crate::Instance for Instance {
+ #[cfg_attr(target_os = "emscripten", allow(unused_variables, unused_mut))]
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result {
+ #[cfg(target_os = "emscripten")]
+ let egl = Arc::new(egl::Instance::new(egl::Static));
+
+ #[cfg(not(target_os = "emscripten"))]
let egl = match egl::DynamicInstance::::load_required() {
Ok(egl) => Arc::new(egl),
Err(e) => {
@@ -528,6 +548,7 @@ impl crate::Instance for Instance {
None
};
+ #[cfg(not(target_os = "emscripten"))]
let display = if let (Some(library), Some(egl)) =
(wayland_library, egl.upcast::())
{
@@ -553,6 +574,9 @@ impl crate::Instance for Instance {
egl.get_display(egl::DEFAULT_DISPLAY).unwrap()
};
+ #[cfg(target_os = "emscripten")]
+ let display = egl.get_display(egl::DEFAULT_DISPLAY).unwrap();
+
if desc.flags.contains(crate::InstanceFlags::VALIDATION)
&& client_ext_str.contains(&"EGL_KHR_debug")
{
@@ -582,7 +606,10 @@ impl crate::Instance for Instance {
})
}
- #[cfg_attr(target_os = "macos", allow(unused, unused_mut, unreachable_code))]
+ #[cfg_attr(
+ any(target_os = "macos", target_os = "emscripten"),
+ allow(unused, unused_mut, unreachable_code)
+ )]
unsafe fn create_surface(
&self,
has_handle: &impl HasRawWindowHandle,
@@ -611,6 +638,7 @@ impl crate::Instance for Instance {
return Err(crate::InstanceError);
}
}
+ #[cfg(not(target_os = "emscripten"))]
Rwh::Wayland(handle) => {
/* Wayland displays are not sharable between surfaces so if the
* surface we receive from this handle is from a different
@@ -645,6 +673,8 @@ impl crate::Instance for Instance {
drop(old_inner);
}
}
+ #[cfg(target_os = "emscripten")]
+ Rwh::Web(_) => {}
other => {
log::error!("Unsupported window: {:?}", other);
return Err(crate::InstanceError);
@@ -736,7 +766,7 @@ pub struct Swapchain {
#[derive(Debug)]
pub struct Surface {
- egl: Arc>,
+ egl: Arc,
wsi_library: Option>,
config: egl::Config,
display: egl::Display,
@@ -875,6 +905,8 @@ impl crate::Surface for Surface {
wl_window = Some(window);
window
}
+ #[cfg(target_os = "emscripten")]
+ Rwh::Web(handle) => handle.id as *mut std::ffi::c_void,
_ => unreachable!(),
};
@@ -900,6 +932,7 @@ impl crate::Surface for Surface {
attributes.push(egl::ATTRIB_NONE as i32);
// Careful, we can still be in 1.4 version even if `upcast` succeeds
+ #[cfg(not(target_os = "emscripten"))]
let raw_result = if let Some(egl) = self.egl.upcast::() {
let attributes_usize = attributes
.into_iter()
@@ -920,6 +953,14 @@ impl crate::Surface for Surface {
)
};
+ #[cfg(target_os = "emscripten")]
+ let raw_result = self.egl.create_window_surface(
+ self.display,
+ self.config,
+ native_window_ptr,
+ Some(&attributes),
+ );
+
match raw_result {
Ok(raw) => (raw, wl_window),
Err(e) => {
diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs
index 1d59b7f7434..26534a8053d 100644
--- a/wgpu-hal/src/gles/mod.rs
+++ b/wgpu-hal/src/gles/mod.rs
@@ -56,9 +56,9 @@ To address this, we invalidate the vertex buffers based on:
*/
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
mod egl;
-#[cfg(target_arch = "wasm32")]
+#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
mod web;
mod adapter;
@@ -67,10 +67,10 @@ mod conv;
mod device;
mod queue;
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
use self::egl::{AdapterContext, Instance, Surface};
-#[cfg(target_arch = "wasm32")]
+#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
use self::web::{AdapterContext, Instance, Surface};
use arrayvec::ArrayVec;
diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs
index 91631f4913b..f2a517af0e3 100644
--- a/wgpu-hal/src/gles/queue.rs
+++ b/wgpu-hal/src/gles/queue.rs
@@ -1102,10 +1102,10 @@ impl crate::Queue for super::Queue {
surface: &mut super::Surface,
texture: super::Texture,
) -> Result<(), crate::SurfaceError> {
- #[cfg(not(target_arch = "wasm32"))]
+ #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
let gl = &self.shared.context.get_without_egl_lock();
- #[cfg(target_arch = "wasm32")]
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
let gl = &self.shared.context.glow_context;
surface.present(texture, gl)
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml
index d92961d5db3..b319494aa60 100644
--- a/wgpu/Cargo.toml
+++ b/wgpu/Cargo.toml
@@ -83,13 +83,13 @@ trace = ["serde", "wgc/trace"]
replay = ["serde", "wgc/replay"]
webgl = ["wgc"]
-[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc]
+[target.'cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))'.dependencies.wgc]
package = "wgpu-core"
path = "../wgpu-core"
version = "0.11"
features = ["raw-window-handle"]
-[target.'cfg(target_arch = "wasm32")'.dependencies.wgc]
+[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies.wgc]
package = "wgpu-core"
path = "../wgpu-core"
version = "0.11"
@@ -101,7 +101,7 @@ package = "wgpu-types"
path = "../wgpu-types"
version = "0.11"
-[target.'cfg(not(target_arch = "wasm32"))'.dependencies.hal]
+[target.'cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))'.dependencies.hal]
package = "wgpu-hal"
path = "../wgpu-hal"
version = "0.11"
@@ -126,9 +126,11 @@ noise = { version = "0.7", default-features = false }
obj = "0.10"
png = "0.16"
rand = "0.7.2"
+
+[target.'cfg(not(target_os = "emscripten"))'.dev-dependencies]
winit = "0.26"
-[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
+[target.'cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))'.dev-dependencies]
async-executor = "1.0"
pollster = "0.2"
env_logger = "0.8"
@@ -152,7 +154,7 @@ rev = "29571cc"
#version = "0.7"
features = ["wgsl-out"]
-[target.'cfg(target_arch = "wasm32")'.dependencies]
+[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
wasm-bindgen = "0.2.76" # remember to change version in wiki as well
web-sys = { version = "0.3.53", features = [
"Document",
@@ -283,7 +285,7 @@ wasm-bindgen-futures = "0.4.23"
# enable parking_lot's wasm-bindgen feature so that it, in turn, enables that of crate `instant`
parking_lot = { version = "0.11", features = ["wasm-bindgen"] }
-[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
+[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dev-dependencies]
console_error_panic_hook = "0.1.6"
console_log = "0.1.2"
# We need the Location feature in the framework examples
diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs
index 885ca20127a..b049cae8147 100644
--- a/wgpu/examples/hello-triangle/main.rs
+++ b/wgpu/examples/hello-triangle/main.rs
@@ -1,11 +1,40 @@
+#[cfg(target_os = "emscripten")]
+use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use std::borrow::Cow;
+#[cfg(not(target_os = "emscripten"))]
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::Window,
};
-async fn run(event_loop: EventLoop<()>, window: Window) {
+#[cfg(target_os = "emscripten")]
+struct Window {}
+
+#[cfg(target_os = "emscripten")]
+struct Size {
+ width: u32,
+ height: u32,
+}
+
+#[cfg(target_os = "emscripten")]
+impl Window {
+ fn inner_size(self: &Window) -> Size {
+ Size {
+ width: 640,
+ height: 400,
+ }
+ }
+}
+
+#[cfg(target_os = "emscripten")]
+unsafe impl HasRawWindowHandle for Window {
+ fn raw_window_handle(&self) -> RawWindowHandle {
+ RawWindowHandle::Web(raw_window_handle::WebHandle::empty())
+ }
+}
+
+async fn run(#[cfg(not(target_os = "emscripten"))] event_loop: EventLoop<()>, window: Window) {
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::Backends::all());
let surface = unsafe { instance.create_surface(&window) };
@@ -67,6 +96,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
multiview: None,
});
+ #[cfg_attr(target_os = "emscripten", allow(unused_mut))]
let mut config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: swapchain_format,
@@ -77,6 +107,45 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
surface.configure(&device, &config);
+ fn redraw(
+ surface: &wgpu::Surface,
+ device: &wgpu::Device,
+ render_pipeline: &wgpu::RenderPipeline,
+ queue: &wgpu::Queue,
+ ) {
+ let frame = surface
+ .get_current_texture()
+ .expect("Failed to acquire next swap chain texture");
+ let view = frame
+ .texture
+ .create_view(&wgpu::TextureViewDescriptor::default());
+ let mut encoder =
+ device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
+ {
+ let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+ label: None,
+ color_attachments: &[wgpu::RenderPassColorAttachment {
+ view: &view,
+ resolve_target: None,
+ ops: wgpu::Operations {
+ load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
+ store: true,
+ },
+ }],
+ depth_stencil_attachment: None,
+ });
+ rpass.set_pipeline(render_pipeline);
+ rpass.draw(0..3, 0..1);
+ }
+
+ queue.submit(Some(encoder.finish()));
+ frame.present();
+ }
+
+ #[cfg(target_os = "emscripten")]
+ redraw(&surface, &device, &render_pipeline, &queue);
+
+ #[cfg(not(target_os = "emscripten"))]
event_loop.run(move |event, _, control_flow| {
// Have the closure take ownership of the resources.
// `event_loop.run` never returns, therefore we must do this to ensure
@@ -94,35 +163,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
config.height = size.height;
surface.configure(&device, &config);
}
- Event::RedrawRequested(_) => {
- let frame = surface
- .get_current_texture()
- .expect("Failed to acquire next swap chain texture");
- let view = frame
- .texture
- .create_view(&wgpu::TextureViewDescriptor::default());
- let mut encoder =
- device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
- {
- let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
- label: None,
- color_attachments: &[wgpu::RenderPassColorAttachment {
- view: &view,
- resolve_target: None,
- ops: wgpu::Operations {
- load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
- store: true,
- },
- }],
- depth_stencil_attachment: None,
- });
- rpass.set_pipeline(&render_pipeline);
- rpass.draw(0..3, 0..1);
- }
-
- queue.submit(Some(encoder.finish()));
- frame.present();
- }
+ Event::RedrawRequested(_) => redraw(&surface, &device, &render_pipeline, &queue),
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
@@ -133,16 +174,18 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
}
fn main() {
- let event_loop = EventLoop::new();
- let window = winit::window::Window::new(&event_loop).unwrap();
#[cfg(not(target_arch = "wasm32"))]
{
+ let event_loop = EventLoop::new();
+ let window = winit::window::Window::new(&event_loop).unwrap();
env_logger::init();
// Temporarily avoid srgb formats for the swapchain on the web
pollster::block_on(run(event_loop, window));
}
- #[cfg(target_arch = "wasm32")]
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
{
+ let event_loop = EventLoop::new();
+ let window = winit::window::Window::new(&event_loop).unwrap();
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger");
use winit::platform::web::WindowExtWebSys;
@@ -157,4 +200,21 @@ fn main() {
.expect("couldn't append canvas to document body");
wasm_bindgen_futures::spawn_local(run(event_loop, window));
}
+ #[cfg(target_os = "emscripten")]
+ {
+ use env_logger::Builder;
+ use log::LevelFilter;
+
+ let window = Window {};
+ Builder::new()
+ .format(|_buf, record| {
+ let message = format!("{}: {}", record.level(), record.args());
+ println!("{}", &message);
+ Ok(())
+ })
+ .filter(None, LevelFilter::Info)
+ .init();
+
+ pollster::block_on(run(window));
+ }
}
diff --git a/wgpu/src/backend/mod.rs b/wgpu/src/backend/mod.rs
index e73d66ad895..bf08cb5f334 100644
--- a/wgpu/src/backend/mod.rs
+++ b/wgpu/src/backend/mod.rs
@@ -1,12 +1,32 @@
-#[cfg(all(target_arch = "wasm32", not(feature = "webgl")))]
+#[cfg(all(
+ target_arch = "wasm32",
+ not(target_os = "emscripten"),
+ not(feature = "webgl")
+))]
mod web;
-#[cfg(all(target_arch = "wasm32", not(feature = "webgl")))]
+#[cfg(all(
+ target_arch = "wasm32",
+ not(target_os = "emscripten"),
+ not(feature = "webgl")
+))]
pub(crate) use web::{BufferMappedRange, Context};
-#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
+#[cfg(any(
+ not(target_arch = "wasm32"),
+ target_os = "emscripten",
+ feature = "webgl"
+))]
mod direct;
-#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
+#[cfg(any(
+ not(target_arch = "wasm32"),
+ target_os = "emscripten",
+ feature = "webgl"
+))]
pub(crate) use direct::{BufferMappedRange, Context};
-#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
+#[cfg(any(
+ not(target_arch = "wasm32"),
+ target_os = "emscripten",
+ feature = "webgl"
+))]
mod native_gpu_future;
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 82869e020ad..3a97e213071 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -1511,7 +1511,11 @@ impl Instance {
/// # Safety
///
/// - canvas must be a valid