mirror of https://github.com/sotrh/learn-wgpu
wasm is building
parent
e683f9de4c
commit
0da913d253
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# Adapted from https://github.com/gfx-rs/wgpu/blob/master/run-wasm-example.sh
|
||||
|
||||
set -e
|
||||
|
||||
cargo build --bin pong --target wasm32-unknown-unknown
|
||||
|
||||
mkdir -p target/wasm-examples/pong
|
||||
wasm-bindgen --target web --out-dir target/wasm-examples/pong target/wasm32-unknown-unknown/debug/pong.wasm
|
||||
cp index.template.html target/wasm-examples/pong/index.html
|
@ -1,81 +1,97 @@
|
||||
use anyhow::*;
|
||||
use fs_extra::copy_items;
|
||||
use fs_extra::dir::CopyOptions;
|
||||
use glob::glob;
|
||||
use std::fs::{read_to_string, write};
|
||||
use std::path::PathBuf;
|
||||
use naga::back::wgsl;
|
||||
use naga::front::glsl::Options;
|
||||
use naga::front::glsl::Parser;
|
||||
use rayon::prelude::*;
|
||||
use std::env;
|
||||
use std::{fs::read_to_string, path::PathBuf};
|
||||
|
||||
struct ShaderData {
|
||||
src: String,
|
||||
src_path: PathBuf,
|
||||
spv_path: PathBuf,
|
||||
kind: shaderc::ShaderKind,
|
||||
}
|
||||
pub fn load_shader(src_path: PathBuf) -> Result<()> {
|
||||
let extension = src_path
|
||||
.extension()
|
||||
.context("File has no extension")?
|
||||
.to_str()
|
||||
.context("Extension cannot be converted to &str")?;
|
||||
let kind = match extension {
|
||||
"vert" => naga::ShaderStage::Vertex,
|
||||
"frag" => naga::ShaderStage::Fragment,
|
||||
"comp" => naga::ShaderStage::Compute,
|
||||
_ => bail!("Unsupported shader: {}", src_path.display()),
|
||||
};
|
||||
|
||||
let src = read_to_string(src_path.clone())?;
|
||||
// let spv_path = src_path.with_extension(format!("{}.spv", extension));
|
||||
let wgsl_path = src_path.with_extension(format!("{}.wgsl", extension));
|
||||
|
||||
let mut parser = Parser::default();
|
||||
let options = Options::from(kind);
|
||||
let module = match parser.parse(&options, &src) {
|
||||
Ok(it) => it,
|
||||
Err(errors) => {
|
||||
bail!(
|
||||
"Failed to compile shader: {}\nErrors:\n{:#?}",
|
||||
src_path.display(),
|
||||
errors
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
impl ShaderData {
|
||||
pub fn load(src_path: PathBuf) -> Result<Self> {
|
||||
let extension = src_path
|
||||
.extension()
|
||||
.context("File has no extension")?
|
||||
.to_str()
|
||||
.context("Extension cannot be converted to &str")?;
|
||||
let kind = match extension {
|
||||
"vert" => shaderc::ShaderKind::Vertex,
|
||||
"frag" => shaderc::ShaderKind::Fragment,
|
||||
"comp" => shaderc::ShaderKind::Compute,
|
||||
_ => bail!("Unsupported shader: {}", src_path.display()),
|
||||
};
|
||||
let info = naga::valid::Validator::new(
|
||||
naga::valid::ValidationFlags::all(),
|
||||
naga::valid::Capabilities::empty(),
|
||||
)
|
||||
.validate(&module)?;
|
||||
std::fs::write(wgsl_path, wgsl::write_string(&module, &info)?)?;
|
||||
|
||||
let src = read_to_string(src_path.clone())?;
|
||||
let spv_path = src_path.with_extension(format!("{}.spv", extension));
|
||||
// let flags = spv::WriterFlags::DEBUG | spv::WriterFlags::ADJUST_COORDINATE_SPACE;
|
||||
// let options = spv::Options {
|
||||
// flags,
|
||||
// ..Default::default()
|
||||
// };
|
||||
// let spv = spv::write_vec(&module, &info, &options)?;
|
||||
// let dis = rspirv::dr::load_words(spv)
|
||||
// .expect("Unable to disassemble shader")
|
||||
// .disassemble();
|
||||
// std::fs::write(spv_path, &spv)?;
|
||||
|
||||
Ok(Self {
|
||||
src,
|
||||
src_path,
|
||||
spv_path,
|
||||
kind,
|
||||
})
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// This tells cargo to rerun this script if something in /src/ changes.
|
||||
println!("cargo:rerun-if-changed=src/*");
|
||||
|
||||
// Collect all shaders recursively within /src/
|
||||
let mut shader_paths = [
|
||||
glob("./res/**/*.vert")?,
|
||||
glob("./res/**/*.frag")?,
|
||||
glob("./res/**/*.comp")?,
|
||||
];
|
||||
// UDPATED!
|
||||
let shader_paths = {
|
||||
let mut data = Vec::new();
|
||||
data.extend(glob("./res/**/*.vert")?);
|
||||
data.extend(glob("./res/**/*.frag")?);
|
||||
data.extend(glob("./res/**/*.comp")?);
|
||||
data
|
||||
};
|
||||
|
||||
// This could be parallelized
|
||||
let shaders = shader_paths
|
||||
.iter_mut()
|
||||
.flatten()
|
||||
.map(|glob_result| ShaderData::load(glob_result?))
|
||||
// UPDATED!
|
||||
// This is parallelized
|
||||
shader_paths
|
||||
.into_par_iter()
|
||||
.map(|glob_result| load_shader(glob_result?))
|
||||
.collect::<Vec<Result<_>>>()
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let mut compiler = shaderc::Compiler::new().context("Unable to create shader compiler")?;
|
||||
|
||||
// This can't be parallelized. The [shaderc::Compiler] is not
|
||||
// thread safe. Also, it creates a lot of resources. You could
|
||||
// spawn multiple processes to handle this, but it would probably
|
||||
// be better just to only compile shaders that have been changed
|
||||
// recently.
|
||||
for shader in shaders {
|
||||
// This tells cargo to rerun this script if something in /src/ changes.
|
||||
println!(
|
||||
"cargo:rerun-if-changed={}",
|
||||
shader.src_path.as_os_str().to_str().unwrap()
|
||||
);
|
||||
// This tells cargo to rerun this script if something in /res/ changes.
|
||||
println!("cargo:rerun-if-changed=res/*");
|
||||
|
||||
let compiled = compiler.compile_into_spirv(
|
||||
&shader.src,
|
||||
shader.kind,
|
||||
shader.src_path.to_str().unwrap(),
|
||||
"main",
|
||||
None,
|
||||
)?;
|
||||
write(shader.spv_path, compiled.as_binary_u8())?;
|
||||
}
|
||||
let out_dir = env::var("OUT_DIR")?;
|
||||
let mut copy_options = CopyOptions::new();
|
||||
let mut paths_to_copy = Vec::new();
|
||||
copy_options.overwrite = true;
|
||||
paths_to_copy.push("res/");
|
||||
copy_items(&paths_to_copy, out_dir, ©_options)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
struct FragmentOutput {
|
||||
[[location(0)]] fColor: vec4<f32>;
|
||||
};
|
||||
|
||||
var<private> fColor: vec4<f32>;
|
||||
|
||||
fn main1() {
|
||||
fColor = vec4<f32>(f32(1));
|
||||
return;
|
||||
}
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn main() -> FragmentOutput {
|
||||
main1();
|
||||
let e3: vec4<f32> = fColor;
|
||||
return FragmentOutput(e3);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
struct VertexOutput {
|
||||
[[builtin(position)]] member: vec4<f32>;
|
||||
};
|
||||
|
||||
var<private> aPosition1: vec2<f32>;
|
||||
var<private> gl_Position: vec4<f32>;
|
||||
|
||||
fn main1() {
|
||||
let e2: vec2<f32> = aPosition1;
|
||||
gl_Position = vec4<f32>(e2, f32(0), f32(1));
|
||||
return;
|
||||
}
|
||||
|
||||
[[stage(vertex)]]
|
||||
fn main([[location(0)]] aPosition: vec2<f32>) -> VertexOutput {
|
||||
aPosition1 = aPosition;
|
||||
main1();
|
||||
let e5: vec4<f32> = gl_Position;
|
||||
return VertexOutput(e5);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!--
|
||||
This is adapted from https://github.com/gfx-rs/wgpu/blob/master/run-wasm-example.sh
|
||||
|
||||
Eventually I'll have all the examples create there own components for vuepress to
|
||||
use, but this will do for now.
|
||||
-->
|
||||
<script type="module">
|
||||
import init from "./pong.js";
|
||||
window.addEventListener("load", () => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue