From 8d77ac2f8b631e4e118f9c2d69227a17d4fc4250 Mon Sep 17 00:00:00 2001 From: Jay Oster Date: Sat, 5 Jun 2021 18:40:33 -0700 Subject: [PATCH] Rewrite shaders in WGSL (#172) - Fixes #141 --- examples/custom-shader/shaders/README.md | 13 ---- examples/custom-shader/shaders/frag.spv | Bin 2020 -> 0 bytes examples/custom-shader/shaders/noise.wgsl | 73 +++++++++++++++++++++ examples/custom-shader/shaders/shader.frag | 38 ----------- examples/custom-shader/shaders/shader.vert | 39 ----------- examples/custom-shader/shaders/vert.spv | Bin 1200 -> 0 bytes examples/custom-shader/src/renderers.rs | 14 ++-- shaders/README.md | 13 ---- shaders/frag.spv | Bin 684 -> 0 bytes shaders/scale.wgsl | 53 +++++++++++++++ shaders/shader.frag | 13 ---- shaders/shader.vert | 43 ------------ shaders/vert.spv | Bin 1484 -> 0 bytes src/renderers.rs | 14 ++-- 14 files changed, 146 insertions(+), 167 deletions(-) delete mode 100644 examples/custom-shader/shaders/README.md delete mode 100644 examples/custom-shader/shaders/frag.spv create mode 100644 examples/custom-shader/shaders/noise.wgsl delete mode 100644 examples/custom-shader/shaders/shader.frag delete mode 100644 examples/custom-shader/shaders/shader.vert delete mode 100644 examples/custom-shader/shaders/vert.spv delete mode 100644 shaders/README.md delete mode 100644 shaders/frag.spv create mode 100644 shaders/scale.wgsl delete mode 100644 shaders/shader.frag delete mode 100644 shaders/shader.vert delete mode 100644 shaders/vert.spv diff --git a/examples/custom-shader/shaders/README.md b/examples/custom-shader/shaders/README.md deleted file mode 100644 index 5be4ff8..0000000 --- a/examples/custom-shader/shaders/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Shaders - -The GLSL shader source is not compiled as part of the normal cargo build process. This was a conscious decision sparked by the current state of the ecosystem; compiling GLSL-to-SPIR-V requires a C++ toolchain including CMake, which is an unacceptable constraint for a simple crate providing a pixel buffer. - -If you need to modify the GLSL sources, you must also recompile the SPIR-V as well. This can be done with `glslang`, `glslc`, etc. - -Compile shaders with `glslangValidator`: - -```bash -glslangValidator -V shader.frag && glslangValidator -V shader.vert -``` - -For more information, see https://github.com/parasyte/pixels/issues/9 diff --git a/examples/custom-shader/shaders/frag.spv b/examples/custom-shader/shaders/frag.spv deleted file mode 100644 index aee9847df644e5f981aa9d90f17c4905c6d88c4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2020 zcmYk7OH)%p5QPWA<^7b01tLr_c2C^vn&h>ft(Ls!YB9_DwW8OtlzenoO;=$<%IYvQ*AZ z&dfeU(Q0B=h^EcdnHpJ8$R3>#K=eXrmkwSVXckjeW4>!qAhuE;h-p-;m_5mbh0(*Q zB{VV9Anrm4l%f4Ho;lASOpl%)PD>T(+GI=RDDQygr`ck*U}LrBHnD8s^f;ee50As5 zT)Y2>Y&jEA)H9Cm(huwz&NF-Yi}f%p=2#P$S!qtfqf*{wV%@yBRCtg*E*W(zu)ZjB zmf1Th{ihF%&5D|a zBTAZ>t&{sePkoj7@X6=n+@;UgDHeXv-e{!h(Y#h%+@i+bH+K#r+?mX^w8paro%)xg$oudUaox9B3cNvIjMz z#pnLusQZyDb@9capOK|*_yMuJKjOp|Wa%j!x$wD5xNiB6W#a<5=^MWNh-6v+L>4Xi zd|#hx{;TcBs`nG}-*1&x&~Iu^UG$Ls@Odk6?DtwWE-+Y+zbz1-(><{l_rZYsBPNg~ z*RU+#E@#E(+DRJAkLe>CdbeWd#(a?mf7NmH@}uL{98W*f;;3a^fCrx(_e^v4 zBt|`)8E(<#d9Hc80H4-wyo;m&@4-5H2TzSdvM&YBwym#|HLn~8&!`fr1@y#I0y(G) ze@kEuJiXvv(n6H;suw$s-*NT6kcFRt E|1UUz0RR91 diff --git a/examples/custom-shader/shaders/noise.wgsl b/examples/custom-shader/shaders/noise.wgsl new file mode 100644 index 0000000..cdde83c --- /dev/null +++ b/examples/custom-shader/shaders/noise.wgsl @@ -0,0 +1,73 @@ +// Vertex shader bindings + +struct VertexOutput { + [[location(0)]] tex_coord: vec2; + [[builtin(position)]] position: vec4; +}; + +let positions: array, 6> = array, 6>( + // Upper left triangle + vec2(-1.0, -1.0), + vec2(1.0, -1.0), + vec2(-1.0, 1.0), + + // Lower right triangle + vec2(-1.0, 1.0), + vec2(1.0, -1.0), + vec2(1.0, 1.0), +); + +let uv: array, 6> = array, 6>( + // Upper left triangle + vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + + // Lower right triangle + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(1.0, 1.0), +); + +[[stage(vertex)]] +fn vs_main([[builtin(vertex_index)]] vertex_index: u32) -> VertexOutput { + var out: VertexOutput; + out.tex_coord = uv[vertex_index]; + out.position = vec4(positions[vertex_index], 0.0, 1.0); + return out; +} + +// Fragment shader bindings + +[[group(0), binding(0)]] var r_tex_color: texture_2d; +[[group(0), binding(1)]] var r_tex_sampler: sampler; +[[block]] struct Locals { + time: f32; +}; +[[group(0), binding(2)]] var r_locals: Locals; + +let tau: f32 = 6.283185307179586476925286766559; +let bias: f32 = 0.2376; // Offset the circular time input so it is never 0 + +// Random functions based on https://thebookofshaders.com/10/ +let random_scale: f32 = 43758.5453123; +let random_x: f32 = 12.9898; +let random_y: f32 = 78.233; + +fn random(x: f32) -> f32 { + return fract(sin(x) * random_scale); +} + +fn random_vec2(st: vec2) -> f32 { + return random(dot(st, vec2(random_x, random_y))); +} + +[[stage(fragment)]] +fn fs_main([[location(0)]] tex_coord: vec2) -> [[location(0)]] vec4 { + let sampled_color: vec4 = textureSample(r_tex_color, r_tex_sampler, tex_coord); + let noise_color: vec3 = vec3(random_vec2( + tex_coord.xy * vec2(r_locals.time % tau + bias) + )); + + return vec4(sampled_color.rgb * noise_color, sampled_color.a); +} diff --git a/examples/custom-shader/shaders/shader.frag b/examples/custom-shader/shaders/shader.frag deleted file mode 100644 index 6308c43..0000000 --- a/examples/custom-shader/shaders/shader.frag +++ /dev/null @@ -1,38 +0,0 @@ -// IMPORTANT: This shader needs to be compiled out-of-band to SPIR-V -// See: https://github.com/parasyte/pixels/issues/9 - -#version 450 - -layout(location = 0) in vec2 v_TexCoord; -layout(location = 0) out vec4 outColor; -layout(set = 0, binding = 0) uniform texture2D t_Color; -layout(set = 0, binding = 1) uniform sampler s_Color; -layout(set = 0, binding = 2) uniform Locals { - float u_Time; -}; - -#define PI 3.1415926535897932384626433832795 -#define TAU PI * 2.0 - -// Offset the circular time input so it is never 0 -#define BIAS 0.2376 - -// Random functions based on https://thebookofshaders.com/10/ -#define RANDOM_SCALE 43758.5453123 -#define RANDOM_X 12.9898 -#define RANDOM_Y 78.233 - -float random(float x) { - return fract(sin(x) * RANDOM_SCALE); -} - -float random_vec2(vec2 st) { - return random(dot(st.xy, vec2(RANDOM_X, RANDOM_Y))); -} - -void main() { - vec4 sampledColor = texture(sampler2D(t_Color, s_Color), v_TexCoord.xy); - vec3 noiseColor = vec3(random_vec2(v_TexCoord.xy * vec2(mod(u_Time, TAU) + BIAS))); - - outColor = vec4(sampledColor.rgb * noiseColor, sampledColor.a); -} diff --git a/examples/custom-shader/shaders/shader.vert b/examples/custom-shader/shaders/shader.vert deleted file mode 100644 index 8804d9d..0000000 --- a/examples/custom-shader/shaders/shader.vert +++ /dev/null @@ -1,39 +0,0 @@ -// IMPORTANT: This shader needs to be compiled out-of-band to SPIR-V -// See: https://github.com/parasyte/pixels/issues/9 - -#version 450 - -out gl_PerVertex { - vec4 gl_Position; -}; - -layout(location = 0) out vec2 v_TexCoord; - -const vec2 positions[6] = vec2[6]( - // Upper left triangle - vec2(-1.0, -1.0), - vec2(1.0, -1.0), - vec2(-1.0, 1.0), - - // Lower right triangle - vec2(-1.0, 1.0), - vec2(1.0, -1.0), - vec2(1.0, 1.0) -); - -const vec2 uv[6] = vec2[6]( - // Upper left triangle - vec2(0.0, 0.0), - vec2(1.0, 0.0), - vec2(0.0, 1.0), - - // Lower right triangle - vec2(0.0, 1.0), - vec2(1.0, 0.0), - vec2(1.0, 1.0) -); - -void main() { - v_TexCoord = uv[gl_VertexIndex]; - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); -} diff --git a/examples/custom-shader/shaders/vert.spv b/examples/custom-shader/shaders/vert.spv deleted file mode 100644 index ec125ed9ba186c2f833671f9eaa8d58e8c42c4f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1200 zcmYk5T~AX%5Qeuct$ZkmDENVR5ET?GTp%GaY6utAgo_dhw*=D@(*)b3G^CgOGZKFl zHzYjIp0i1}d6}7a-<_SAv(&0<4??JfNq#$_So5I@6T(brMB6(0ebl@hcAC3iqGUGI zqEO8o=Ufxu-+8yEKLr*+25S7O*#C&@sK#}57`0btC;8~G-yd|;G~(I67iXvWV3?17 z^*Z@Tz8+qn?HZo{xybR=u3*u&^Fbjege`b|_xhLJVYlByUyC)#n{NX~FMNT<;T;Q*EHFjNai}($=3@nk4VaHfqM(p&Qru^43wg$Op#M9Ue zxHik!yUn>w{1EF|Irrrs0oNAwx;G2tMAFRRhj9HPX&w{FsY%>?8OtZ`3BGZ`O~v~c zh`qxco)P+L?cpgl1C?ke;0j;fo{gPz+JBC3-S*~;UY4<(GklG;Pv6oClXCuYYTsa; zot(LiGazU0-nj}~X%=r|bbXV0TqBkfiF=1{&*R+tG9I7B2RP5GcVFl`3+roQt;Krx z_&!yveYoUrVd_|GcMiUJ`%bZM*7#f5%M!k``_5^#ev1P#II~wkPK|ocEdzP=zBA*L zYaKu3@*aChxjy2{sY$u~pO8Q1KEKB%kaHz&3tz4R+EifQpMhHUd~eRrdz{TS$bjF- M8jaQ8kzpU)19%}oV*mgE diff --git a/examples/custom-shader/src/renderers.rs b/examples/custom-shader/src/renderers.rs index 705314a..ebc7d71 100644 --- a/examples/custom-shader/src/renderers.rs +++ b/examples/custom-shader/src/renderers.rs @@ -1,4 +1,5 @@ use pixels::wgpu::{self, util::DeviceExt}; +use std::borrow::Cow; pub(crate) struct NoiseRenderer { bind_group: wgpu::BindGroup, @@ -8,8 +9,13 @@ pub(crate) struct NoiseRenderer { impl NoiseRenderer { pub(crate) fn new(device: &wgpu::Device, texture_view: &wgpu::TextureView) -> Self { - let vs_module = device.create_shader_module(&wgpu::include_spirv!("../shaders/vert.spv")); - let fs_module = device.create_shader_module(&wgpu::include_spirv!("../shaders/frag.spv")); + let shader = wgpu::ShaderModuleDescriptor { + label: Some("custom_noise_shader"), + source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("../shaders/noise.wgsl"))), + flags: wgpu::ShaderFlags::VALIDATION, + }; + let vs_module = device.create_shader_module(&shader); + let fs_module = device.create_shader_module(&shader); // Create a texture sampler with nearest neighbor let sampler = device.create_sampler(&wgpu::SamplerDescriptor { @@ -103,7 +109,7 @@ impl NoiseRenderer { layout: Some(&pipeline_layout), vertex: wgpu::VertexState { module: &vs_module, - entry_point: "main", + entry_point: "vs_main", buffers: &[], }, primitive: wgpu::PrimitiveState::default(), @@ -111,7 +117,7 @@ impl NoiseRenderer { multisample: wgpu::MultisampleState::default(), fragment: Some(wgpu::FragmentState { module: &fs_module, - entry_point: "main", + entry_point: "fs_main", targets: &[wgpu::ColorTargetState { format: wgpu::TextureFormat::Bgra8UnormSrgb, blend: Some(wgpu::BlendState { diff --git a/shaders/README.md b/shaders/README.md deleted file mode 100644 index 5be4ff8..0000000 --- a/shaders/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Shaders - -The GLSL shader source is not compiled as part of the normal cargo build process. This was a conscious decision sparked by the current state of the ecosystem; compiling GLSL-to-SPIR-V requires a C++ toolchain including CMake, which is an unacceptable constraint for a simple crate providing a pixel buffer. - -If you need to modify the GLSL sources, you must also recompile the SPIR-V as well. This can be done with `glslang`, `glslc`, etc. - -Compile shaders with `glslangValidator`: - -```bash -glslangValidator -V shader.frag && glslangValidator -V shader.vert -``` - -For more information, see https://github.com/parasyte/pixels/issues/9 diff --git a/shaders/frag.spv b/shaders/frag.spv deleted file mode 100644 index 46bcca49c0f5a2d4feba7740ad0f81dfe974d895..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684 zcmYk3OG`pg6oq%1kFtDZX%>XmTpCmaQ4!m#9}of2NO|=Vw#7e+fjcupY+epPgPVSp9-+x2JG@wjrihH0XC~Iz<4KlpAV9kWXd+xY?0^V1?8POc=m@2smI6o?&))o zB-2U65RG+?2$$Fz$0_>9y$rTy_FU|_vw7b+R`r@p;0(QVnn?F8_C>fZ(MIpAV(07f zEt7pM`Ku+iN4XB&Zj#mOmt8Atjmq*stu@5X; + [[builtin(position)]] position: vec4; +}; + +[[block]] struct Locals { + transform: mat4x4; +}; +[[group(0), binding(2)]] var r_locals: Locals; + +let positions: array, 6> = array, 6>( + // Upper left triangle + vec2(-1.0, -1.0), + vec2(1.0, -1.0), + vec2(-1.0, 1.0), + + // Lower right triangle + vec2(-1.0, 1.0), + vec2(1.0, -1.0), + vec2(1.0, 1.0), +); + +let uv: array, 6> = array, 6>( + // Upper left triangle + vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + + // Lower right triangle + vec2(0.0, 1.0), + vec2(1.0, 0.0), + vec2(1.0, 1.0), +); + +[[stage(vertex)]] +fn vs_main([[builtin(vertex_index)]] vertex_index: u32) -> VertexOutput { + var out: VertexOutput; + out.tex_coord = uv[vertex_index]; + out.position = r_locals.transform * vec4(positions[vertex_index], 0.0, 1.0); + return out; +} + +// Fragment shader bindings + +[[group(0), binding(0)]] var r_tex_color: texture_2d; +[[group(0), binding(1)]] var r_tex_sampler: sampler; + +[[stage(fragment)]] +fn fs_main([[location(0)]] tex_coord: vec2) -> [[location(0)]] vec4 { + return textureSample(r_tex_color, r_tex_sampler, tex_coord); +} diff --git a/shaders/shader.frag b/shaders/shader.frag deleted file mode 100644 index 65853cf..0000000 --- a/shaders/shader.frag +++ /dev/null @@ -1,13 +0,0 @@ -// IMPORTANT: This shader needs to be compiled out-of-band to SPIR-V -// See: https://github.com/parasyte/pixels/issues/9 - -#version 450 - -layout(location = 0) in vec2 v_TexCoord; -layout(location = 0) out vec4 outColor; -layout(set = 0, binding = 0) uniform texture2D t_Color; -layout(set = 0, binding = 1) uniform sampler s_Color; - -void main() { - outColor = texture(sampler2D(t_Color, s_Color), v_TexCoord); -} diff --git a/shaders/shader.vert b/shaders/shader.vert deleted file mode 100644 index 3e1d026..0000000 --- a/shaders/shader.vert +++ /dev/null @@ -1,43 +0,0 @@ -// IMPORTANT: This shader needs to be compiled out-of-band to SPIR-V -// See: https://github.com/parasyte/pixels/issues/9 - -#version 450 - -out gl_PerVertex { - vec4 gl_Position; -}; - -layout(location = 0) out vec2 v_TexCoord; - -layout(set = 0, binding = 2) uniform Locals { - mat4 u_Transform; -}; - -const vec2 positions[6] = vec2[6]( - // Upper left triangle - vec2(-1.0, -1.0), - vec2(1.0, -1.0), - vec2(-1.0, 1.0), - - // Lower right triangle - vec2(-1.0, 1.0), - vec2(1.0, -1.0), - vec2(1.0, 1.0) -); - -const vec2 uv[6] = vec2[6]( - // Upper left triangle - vec2(0.0, 0.0), - vec2(1.0, 0.0), - vec2(0.0, 1.0), - - // Lower right triangle - vec2(0.0, 1.0), - vec2(1.0, 0.0), - vec2(1.0, 1.0) -); - -void main() { - v_TexCoord = uv[gl_VertexIndex]; - gl_Position = u_Transform * vec4(positions[gl_VertexIndex], 0.0, 1.0); -} diff --git a/shaders/vert.spv b/shaders/vert.spv deleted file mode 100644 index 9c8f317fa61a865096195c68b4f30590d9f5f2fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1484 zcmYk5T~AX%5Qeuc1uF_73aE&u)^D(&0+JXt#*1Ro3yj3urrK(nls0Lr=_P-`Uu5F1 z^2WsHIp=KBB`-7c?z^)yv!|tEZ6Sn0SO^!wQOMRxD8huW80J&kXntze$CFNd|6otW zQYfWDHOriH&4IIaZ=hcRYajt7{)*T?h|8#Eb!8Z}KU=5W>HFbu)KN2^p8ei$eeRAX z-RXxxr#qD|hZ|^nhV3u?F233=EZURqD3cSyX1u<8!*OrY8xGKy(wgM0rG{+|zqb41 z?2NJNN9%Od9*n;YM`!7o`x%X24!iiXH8jX$57yx_w)aKw1RQfF?#a0t)FJ0wj`KR? z%V}Ir>oSh@m?Qc;R=5JpA!iQnw8p!@72_(t`>XudRykA3xi!3b`~<9X-n_=@5@KIf zt^BJzwoke1#22v%aBb(Y{h4Ev_!8E$a_-At2Cg0Yac>F8iKtn|58?c6)Yz+>n#ir> zv3%sN;u~jNCB1)@*gMSO8KJM%9y`T*khCe7gs^uRhN8 zF@6Z=zvI08HswU*w(*_cEVq-#vvYk4=Xv$+3w`HmeTP{4vi?Kf+Pdt+CI1)3Z{6CR zslRJy7~|bMe$BpfSqHwu8&0eBUEh(x`QHL^YSf!&6UeKt Self { - let vs_module = device.create_shader_module(&wgpu::include_spirv!("../shaders/vert.spv")); - let fs_module = device.create_shader_module(&wgpu::include_spirv!("../shaders/frag.spv")); + let shader = wgpu::ShaderModuleDescriptor { + label: Some("pixels_scaling_renderer_shader"), + source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("../shaders/scale.wgsl"))), + flags: wgpu::ShaderFlags::VALIDATION, + }; + let vs_module = device.create_shader_module(&shader); + let fs_module = device.create_shader_module(&shader); // Create a texture sampler with nearest neighbor let sampler = device.create_sampler(&wgpu::SamplerDescriptor { @@ -121,7 +127,7 @@ impl ScalingRenderer { layout: Some(&pipeline_layout), vertex: wgpu::VertexState { module: &vs_module, - entry_point: "main", + entry_point: "vs_main", buffers: &[], }, primitive: wgpu::PrimitiveState::default(), @@ -129,7 +135,7 @@ impl ScalingRenderer { multisample: wgpu::MultisampleState::default(), fragment: Some(wgpu::FragmentState { module: &fs_module, - entry_point: "main", + entry_point: "fs_main", targets: &[wgpu::ColorTargetState { format: render_texture_format, blend: Some(wgpu::BlendState {