troubleshooting wasm failure

web2
Ben Hansen 2 years ago
parent 05767326d9
commit 9811c4037e

10
Cargo.lock generated

@ -867,12 +867,6 @@ version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
[[package]]
name = "futures-io"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
[[package]]
name = "futures-sink"
version = "0.3.19"
@ -892,12 +886,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
dependencies = [
"futures-core",
"futures-io",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
@ -2666,7 +2657,6 @@ dependencies = [
"libc",
"memchr",
"mio 0.7.14",
"num_cpus",
"pin-project-lite",
"winapi",
]

@ -17,17 +17,17 @@ env_logger = "0.9"
pollster = "0.2"
image = "0.23"
log = "0.4"
tobj = "3.0"
tobj = { version = "3.2", features = ["async"]}
wgpu = "0.12"
winit = "0.26"
[target.'cfg(target_arch = "wasm32")'.dependencies]
reqwest = { version = "0.11", features = ["blocking"] }
console_error_panic_hook = "0.1.6"
console_log = "0.2.0"
reqwest = { version = "0.11" }
console_error_panic_hook = "0.1"
console_log = "0.2"
wgpu = { version = "0.12", features = ["webgl"]}
wasm-bindgen = "0.2.76"
web-sys = { version = "0.3.53", features = [
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = [
"Document",
"Window",
"Element",

@ -1,6 +1,6 @@
use anyhow::*;
use fs_extra::copy_items;
use fs_extra::dir::{CopyOptions, create_all};
use fs_extra::dir::CopyOptions;
use std::env;
fn main() -> Result<()> {

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WASM Resource Management Demo</title>
</head>
<body>
<div id="wasm-example">
</div>
<script type="module">
import init from "./pkg/tutorial9_models.js";
init().then(() => {
console.log("WASM Loaded");
});
</script>
</body>
</html>

@ -0,0 +1,12 @@
#!/usr/bin/env python3
from http.server import HTTPServer, SimpleHTTPRequestHandler, test
import sys
class CORSRequestHandler(SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header('Access-Control-Allow-Origin', '*')
SimpleHTTPRequestHandler.end_headers(self)
if __name__ == '__main__':
test(CORSRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)

@ -1,4 +1,4 @@
use std::{iter, str::FromStr};
use std::iter;
use cgmath::prelude::*;
use wgpu::util::DeviceExt;
@ -248,6 +248,7 @@ impl State {
// The instance is a handle to our GPU
// BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU
log::warn!("WGPU setup");
let instance = wgpu::Instance::new(wgpu::Backends::all());
let surface = unsafe { instance.create_surface(window) };
let adapter = instance
@ -258,6 +259,7 @@ impl State {
})
.await
.unwrap();
log::warn!("device and queue");
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
@ -277,6 +279,7 @@ impl State {
.await
.unwrap();
log::warn!("Surface");
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: surface.get_preferred_format(&adapter).unwrap(),
@ -384,6 +387,7 @@ impl State {
label: Some("camera_bind_group"),
});
log::warn!("Load model");
let obj_model = resources::load_model(
"cube.obj",
&device,
@ -592,6 +596,7 @@ pub fn run() {
}
// State::new uses async code, so we're going to wait for it to finish
log::warn!("Creating State");
let mut state = pollster::block_on(State::new(&window));
event_loop.run(move |event, _, control_flow| {

@ -1,8 +1,4 @@
use anyhow::*;
use std::ops::Range;
use std::path::Path;
use tobj::LoadOptions;
use wgpu::util::DeviceExt;
use crate::texture;
@ -64,102 +60,6 @@ pub struct Model {
pub materials: Vec<Material>,
}
impl Model {
pub fn load<P: AsRef<Path>>(
device: &wgpu::Device,
queue: &wgpu::Queue,
layout: &wgpu::BindGroupLayout,
path: P,
) -> Result<Self> {
let (obj_models, obj_materials) = tobj::load_obj(
path.as_ref(),
&LoadOptions {
triangulate: true,
single_index: true,
..Default::default()
},
)?;
let obj_materials = obj_materials?;
// We're assuming that the texture files are stored with the obj file
let containing_folder = path.as_ref().parent().context("Directory has no parent")?;
let mut materials = Vec::new();
for mat in obj_materials {
let diffuse_path = mat.diffuse_texture;
let diffuse_texture =
texture::Texture::load(device, queue, containing_folder.join(diffuse_path))?;
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
},
],
label: None,
});
materials.push(Material {
name: mat.name,
diffuse_texture,
bind_group,
});
}
let mut meshes = Vec::new();
for m in obj_models {
let mut vertices = Vec::new();
for i in 0..m.mesh.positions.len() / 3 {
vertices.push(ModelVertex {
position: [
m.mesh.positions[i * 3],
m.mesh.positions[i * 3 + 1],
m.mesh.positions[i * 3 + 2],
],
tex_coords: [m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1]],
normal: [
m.mesh.normals[i * 3],
m.mesh.normals[i * 3 + 1],
m.mesh.normals[i * 3 + 2],
],
});
}
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Vertex Buffer", path.as_ref())),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Index Buffer", path.as_ref())),
contents: bytemuck::cast_slice(&m.mesh.indices),
usage: wgpu::BufferUsages::INDEX,
});
meshes.push(Mesh {
name: m.name,
vertex_buffer,
index_buffer,
num_elements: m.mesh.indices.len() as u32,
material: m.mesh.material_id.unwrap_or(0),
});
}
Ok(Self { meshes, materials })
}
}
pub trait DrawModel<'a> {
fn draw_mesh(
&mut self,

@ -1,19 +1,20 @@
use std::io::{BufReader, Cursor};
use cfg_if::cfg_if;
use tobj::LoadError;
use wgpu::util::DeviceExt;
use crate::{texture, model};
use crate::{model, texture};
pub async fn load_string(file_name: &str) -> anyhow::Result<String> {
cfg_if! {
if #[cfg(target_arch = "wasm32")] {
log::warn!("Creating url for {}", file_name);
let url = format!("http://127.0.0.1:8080/learn-wgpu/{}", file_name);
let txt = reqwest::get(url)
.await?
.text()
.await?;
log::warn!("Making request for {}", url);
let res = reqwest::get(&url).await?;
log::warn!("Recieved response");
let txt = res.text().await?;
log::warn!("Finished request for {}", url);
} else {
let path = std::path::Path::new(env!("OUT_DIR"))
.join("res")
@ -41,51 +42,50 @@ pub async fn load_binary(file_name: &str) -> anyhow::Result<Vec<u8>> {
let data = std::fs::read(path)?;
}
}
Ok(data)
}
pub async fn load_texture(
file_name: &str,
device: &wgpu::Device,
queue: &wgpu::Queue
queue: &wgpu::Queue,
) -> anyhow::Result<texture::Texture> {
let data = load_binary(file_name).await?;
texture::Texture::from_bytes(device, queue, &data, file_name)
}
pub async fn load_model(
file_name: &str,
device: &wgpu::Device,
queue: &wgpu::Queue,
layout: &wgpu::BindGroupLayout,
) -> anyhow::Result<model::Model> {
log::warn!("Loading obj text");
let obj_text = load_string(file_name).await?;
let obj_cursor = Cursor::new(obj_text);
let mut obj_reader = BufReader::new(obj_cursor);
log::warn!("Loading model: {}", file_name);
let (models, materials) = tobj::load_obj_buf(
log::warn!("Loading model");
let (models, obj_materials) = tobj::load_obj_buf_async(
&mut obj_reader,
&tobj::LoadOptions {
triangulate: true,
single_index: true,
..Default::default()
},
|p| {
log::warn!("Loading material: {:?}", &p);
let mat_path = p.to_str().ok_or(tobj::LoadError::OpenFileFailed)?;
let mat_text = pollster::block_on(load_string(mat_path)).or_else(|_| Err(LoadError::OpenFileFailed))?;
let mat_cursor = Cursor::new(mat_text);
let mut mat_reader = BufReader::new(mat_cursor);
tobj::load_mtl_buf(&mut mat_reader)
}
)?;
|p| async move {
log::warn!("Loading material");
let mat_text = load_string(&p).await.unwrap();
tobj::load_mtl_buf(&mut BufReader::new(Cursor::new(mat_text)))
},
)
.await?;
log::warn!("Creating materials");
let materials = materials?.into_iter().map(|m| {
let diffuse_texture = pollster::block_on(load_texture(&m.diffuse_texture, device, queue))?;
log::warn!("Processing materials");
let mut materials = Vec::new();
for m in obj_materials? {
let diffuse_texture = load_texture(&m.diffuse_texture, device, queue).await?;
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout,
entries: &[
@ -101,53 +101,53 @@ pub async fn load_model(
label: None,
});
Ok(model::Material {
materials.push(model::Material {
name: m.name,
diffuse_texture,
bind_group,
})
}).collect::<anyhow::Result<Vec<_>>>()?;
}
log::warn!("Creating meshes");
let meshes = models.into_iter().map(|m| {
let vertices = (0..m.mesh.positions.len() / 3).map(|i| {
model::ModelVertex {
position: [
m.mesh.positions[i * 3],
m.mesh.positions[i * 3 + 1],
m.mesh.positions[i * 3 + 2],
],
tex_coords: [
m.mesh.texcoords[i * 2],
m.mesh.texcoords[i * 2 + 1],
],
normal: [
m.mesh.normals[i * 3],
m.mesh.normals[i * 3 + 1],
m.mesh.normals[i * 3 + 2],
]
}
}).collect::<Vec<_>>();
let meshes = models
.into_iter()
.map(|m| {
let vertices = (0..m.mesh.positions.len() / 3)
.map(|i| model::ModelVertex {
position: [
m.mesh.positions[i * 3],
m.mesh.positions[i * 3 + 1],
m.mesh.positions[i * 3 + 2],
],
tex_coords: [m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1]],
normal: [
m.mesh.normals[i * 3],
m.mesh.normals[i * 3 + 1],
m.mesh.normals[i * 3 + 2],
],
})
.collect::<Vec<_>>();
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Vertex Buffer", file_name)),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Index Buffer", file_name)),
contents: bytemuck::cast_slice(&m.mesh.indices),
usage: wgpu::BufferUsages::INDEX,
});
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Vertex Buffer", file_name)),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Index Buffer", file_name)),
contents: bytemuck::cast_slice(&m.mesh.indices),
usage: wgpu::BufferUsages::INDEX,
});
model::Mesh {
name: file_name.to_string(),
vertex_buffer,
index_buffer,
num_elements: m.mesh.indices.len() as u32,
material: m.mesh.material_id.unwrap_or(0),
}
}).collect::<Vec<_>>();
model::Mesh {
name: file_name.to_string(),
vertex_buffer,
index_buffer,
num_elements: m.mesh.indices.len() as u32,
material: m.mesh.material_id.unwrap_or(0),
}
})
.collect::<Vec<_>>();
log::warn!("Done with model: {}", file_name);
Ok(model::Model { meshes, materials })

@ -1,6 +1,6 @@
use anyhow::*;
use image::GenericImageView;
use std::{num::NonZeroU32, path::Path};
use std::num::NonZeroU32;
pub struct Texture {
pub texture: wgpu::Texture,
@ -11,19 +11,6 @@ pub struct Texture {
impl Texture {
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;
pub fn load<P: AsRef<Path>>(
device: &wgpu::Device,
queue: &wgpu::Queue,
path: P,
) -> Result<Self> {
// Needed to appease the borrow checker
let path_copy = path.as_ref().to_path_buf();
let label = path_copy.to_str();
let img = image::open(path)?;
Self::from_image(device, queue, &img, label)
}
pub fn create_depth_texture(
device: &wgpu::Device,
config: &wgpu::SurfaceConfiguration,

Loading…
Cancel
Save