Skip to content

Commit

Permalink
HACK: Temporary hack to work around linebender#276
Browse files Browse the repository at this point in the history
Fixed the WASM crashes by reverting to wgpu = 0.14. This surfaced two
more bugs in the repo for which I included fixes. A big issue is
wasm32-unknown-unknown does not support std::time::Instant, so I
implemented a polyfill based on
rust-lang/rust#48564 (comment).
The animated examples, SVG loader, and the frame statistics monitor
won't work in WASM without this. Once there is progress on the wgpu end,
I'll turn that into a proper PR.

Other issues:
* The WGSL won't compile on native since this version of wgpu/naga
  doesn't support `const`. Chrome Canary in WASM works though.
* There are serious visual artifacts in the examples when run in the
  browser.
  • Loading branch information
armansito committed Mar 12, 2023
1 parent dccd59a commit 4f55790
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ moscato = { git = "https://github.com/dfrg/pinot", rev = "59db153" }
peniko = { git = "https://github.com/linebender/peniko", rev = "cafdac9a211a0fb2fec5656bd663d1ac770bcc81" }

[workspace.dependencies]
wgpu = "0.15"
wgpu = "0.14.2"

# Used for examples
clap = "4.1.0"
Expand Down
3 changes: 3 additions & 0 deletions examples/scenes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ clap = { workspace = true, features = ["derive"] }
byte-unit = "4.0"
dialoguer = "0.10"
ureq = "2.6"

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.84"
1 change: 1 addition & 0 deletions examples/scenes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod download;
mod simple_text;
mod svg;
mod test_scenes;
pub mod time;
use std::path::PathBuf;

use anyhow::{anyhow, Result};
Expand Down
3 changes: 1 addition & 2 deletions examples/scenes/src/svg.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use std::{
fs::read_dir,
path::{Path, PathBuf},
time::Instant,
};

use anyhow::{Ok, Result};
use vello::{kurbo::Vec2, SceneBuilder, SceneFragment};
use vello_svg::usvg;

use crate::{ExampleScene, SceneParams, SceneSet};
use crate::{time::Instant, ExampleScene, SceneParams, SceneSet};

pub fn scene_from_files(files: &[PathBuf]) -> Result<SceneSet> {
scene_from_files_inner(files, || ())
Expand Down
101 changes: 101 additions & 0 deletions examples/scenes/src/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Adapted from https://github.com/rust-lang/rust/issues/48564#issuecomment-505114709

#![allow(dead_code, unused_imports)]

use std::convert::TryInto;
use std::ops::{Add, AddAssign, Sub, SubAssign};

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

pub use std::time::*;

#[cfg(not(target_arch = "wasm32"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant(std::time::Instant);

#[cfg(not(target_arch = "wasm32"))]
impl Instant {
pub fn now() -> Self {
Self(std::time::Instant::now())
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
self.0.duration_since(earlier.0)
}
pub fn elapsed(&self) -> Duration {
self.0.elapsed()
}
pub fn checked_add(&self, duration: Duration) -> Option<Self> {
self.0.checked_add(duration).map(|i| Self(i))
}
pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
self.0.checked_sub(duration).map(|i| Self(i))
}
}

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen(inline_js = r#"
export function performance_now() {
return performance.now();
}"#)]
extern "C" {
fn performance_now() -> f64;
}

#[cfg(target_arch = "wasm32")]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant(u64);

#[cfg(target_arch = "wasm32")]
impl Instant {
pub fn now() -> Self {
Self((performance_now() * 1000.0) as u64)
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
Duration::from_micros(self.0 - earlier.0)
}
pub fn elapsed(&self) -> Duration {
Self::now().duration_since(*self)
}
pub fn checked_add(&self, duration: Duration) -> Option<Self> {
match duration.as_micros().try_into() {
Ok(duration) => self.0.checked_add(duration).map(|i| Self(i)),
Err(_) => None,
}
}
pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
match duration.as_micros().try_into() {
Ok(duration) => self.0.checked_sub(duration).map(|i| Self(i)),
Err(_) => None,
}
}
}

impl Add<Duration> for Instant {
type Output = Instant;
fn add(self, other: Duration) -> Instant {
self.checked_add(other).unwrap()
}
}
impl Sub<Duration> for Instant {
type Output = Instant;
fn sub(self, other: Duration) -> Instant {
self.checked_sub(other).unwrap()
}
}
impl Sub<Instant> for Instant {
type Output = Duration;
fn sub(self, other: Instant) -> Duration {
self.duration_since(other)
}
}
impl AddAssign<Duration> for Instant {
fn add_assign(&mut self, other: Duration) {
*self = *self + other;
}
}
impl SubAssign<Duration> for Instant {
fn sub_assign(&mut self, other: Duration) {
*self = *self - other;
}
}
3 changes: 1 addition & 2 deletions examples/with_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
// Also licensed under MIT license, at your choice.

use std::collections::HashSet;
use std::time::Instant;

use anyhow::Result;
use clap::{CommandFactory, Parser};
use scenes::{SceneParams, SceneSet, SimpleText};
use scenes::{time::Instant, SceneParams, SceneSet, SimpleText};
use vello::peniko::Color;
use vello::util::RenderSurface;
use vello::{
Expand Down
8 changes: 5 additions & 3 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ impl Engine {
dimension: wgpu::TextureDimension::D2,
usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
format,
view_formats: &[],
//view_formats: &[],
});
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
label: None,
Expand All @@ -310,7 +310,9 @@ impl Engine {
buffer: &buf,
layout: wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: NonZeroU32::new(image_proxy.width * 4),
bytes_per_row: Some(
NonZeroU32::new(image_proxy.width * 4).unwrap(),
),
rows_per_image: None,
},
},
Expand Down Expand Up @@ -647,7 +649,7 @@ impl BindMap {
dimension: wgpu::TextureDimension::D2,
usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
format,
view_formats: &[],
//view_formats: &[],
});
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
label: None,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ impl TargetTexture {
dimension: wgpu::TextureDimension::D2,
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
format: wgpu::TextureFormat::Rgba8Unorm,
view_formats: &[],
//view_formats: &[],
});
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
Self {
Expand Down
15 changes: 9 additions & 6 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ pub struct DeviceHandle {

impl RenderContext {
pub fn new() -> Result<Self> {
let instance = Instance::new(wgpu::InstanceDescriptor {
let instance = Instance::new(wgpu::Backends::PRIMARY);
/*
wgpu::InstanceDescriptor {
backends: wgpu::Backends::PRIMARY,
dx12_shader_compiler: wgpu::Dx12Compiler::Fxc,
});
});*/
Ok(Self {
instance,
devices: Vec::new(),
Expand All @@ -54,16 +56,17 @@ impl RenderContext {
where
W: HasRawWindowHandle + HasRawDisplayHandle,
{
let surface = unsafe { self.instance.create_surface(window) }.unwrap();
let surface = unsafe { self.instance.create_surface(window) }; //.unwrap();
let dev_id = self.device(Some(&surface)).await.unwrap();

let device_handle = &self.devices[dev_id];
let capabilities = surface.get_capabilities(&device_handle.adapter);
let format = TextureFormat::Bgra8Unorm;
/*let capabilities = surface.get_capabilities(&device_handle.adapter);
let format = capabilities
.formats
.into_iter()
.find(|it| matches!(it, TextureFormat::Rgba8Unorm | TextureFormat::Bgra8Unorm))
.expect("surface should support Rgba8Unorm or Bgra8Unorm");
.expect("surface should support Rgba8Unorm or Bgra8Unorm");*/

let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
Expand All @@ -72,7 +75,7 @@ impl RenderContext {
height,
present_mode: wgpu::PresentMode::Fifo,
alpha_mode: wgpu::CompositeAlphaMode::Auto,
view_formats: vec![],
//view_formats: vec![],
};
surface.configure(&self.devices[dev_id].device, &config);
RenderSurface {
Expand Down

0 comments on commit 4f55790

Please sign in to comment.