Decouple glam from spirv-std (#476)

This commit is contained in:
XAMPPRocky 2021-03-16 09:59:08 +01:00 committed by GitHub
parent eebb2d3b32
commit 6e8453f386
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 446 additions and 233 deletions

87
Cargo.lock generated
View File

@ -170,9 +170,9 @@ checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
[[package]]
name = "byteorder"
version = "1.4.2"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "calloop"
@ -329,7 +329,7 @@ name = "compute-shader"
version = "0.3.0"
dependencies = [
"spirv-std",
"spirv-std-macros",
"spirv-std-macros 0.3.0",
]
[[package]]
@ -1004,12 +1004,12 @@ dependencies = [
[[package]]
name = "glam"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ad8819b352632f676098176a51e11e324e8cee4c2518dd67e58c36b848438e6"
version = "0.13.0"
source = "git+https://github.com/EmbarkStudios/glam-rs.git?branch=spirv-std-impl#41d0c86b16ec22f5a0563f7d7afe1f2404bea9e5"
dependencies = [
"num-traits",
"version_check",
"spirv-std",
"spirv-std-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1056,9 +1056,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "1.6.1"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
dependencies = [
"autocfg",
"hashbrown",
@ -1145,9 +1145,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.86"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
[[package]]
name = "libloading"
@ -1535,21 +1535,23 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.7.0"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10acf907b94fc1b1a152d08ef97e7759650268cf986bf127f387e602b02c7e5a"
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]]
name = "orbclient"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee68c3c79e81d82127e0870f94479675774d34c7ad5b55eecb9c320ef9701187"
checksum = "0c976c5018e7f1db4359616d8b31ef8ae7d9649b11803c0b38fff67fd2999fc8"
dependencies = [
"libc",
"raw-window-handle",
"redox_syscall 0.2.5",
"sdl2",
"sdl2-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
@ -1615,9 +1617,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project-lite"
version = "0.2.4"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827"
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
[[package]]
name = "pin-utils"
@ -1836,14 +1838,13 @@ dependencies = [
[[package]]
name = "regex"
version = "1.4.3"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
@ -1858,9 +1859,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.22"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]]
name = "remove_dir_all"
@ -1980,18 +1981,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.123"
version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.123"
version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
dependencies = [
"proc-macro2",
"quote",
@ -2022,8 +2023,9 @@ dependencies = [
name = "shared"
version = "0.1.0"
dependencies = [
"glam",
"spirv-std",
"spirv-std-macros",
"spirv-std-macros 0.3.0",
]
[[package]]
@ -2036,8 +2038,9 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
name = "simplest-shader"
version = "0.1.0"
dependencies = [
"shared",
"spirv-std",
"spirv-std-macros",
"spirv-std-macros 0.3.0",
]
[[package]]
@ -2046,7 +2049,7 @@ version = "0.1.0"
dependencies = [
"shared",
"spirv-std",
"spirv-std-macros",
"spirv-std-macros 0.3.0",
]
[[package]]
@ -2063,9 +2066,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "smithay-client-toolkit"
version = "0.12.2"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "316e13a3eb853ce7bf72ad3530dc186cb2005c57c521ef5f4ada5ee4eed74de6"
checksum = "4750c76fd5d3ac95fa3ed80fe667d6a3d8590a960e5b575b98eea93339a80b80"
dependencies = [
"andrew",
"bitflags",
@ -2097,14 +2100,24 @@ dependencies = [
name = "spirv-std"
version = "0.3.0"
dependencies = [
"glam",
"num-traits",
"spirv-std-macros",
"spirv-std-macros 0.3.0",
]
[[package]]
name = "spirv-std-macros"
version = "0.3.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "spirv-std-macros"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7ecfdc5a8fc98f8c6071b5b30ce13c896c9268abf04cc53e68cae1ebaf5dc60"
dependencies = [
"quote",
"syn",
@ -2234,9 +2247,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.60"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
dependencies = [
"proc-macro2",
"quote",
@ -2399,9 +2412,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ab8966ac3ca27126141f7999361cc97dd6fb4b71da04c02044fa9045d98bb96"
checksum = "705096c6f83bf68ea5d357a6aa01829ddbdac531b357b45abeca842938085baa"
dependencies = [
"ansi_term 0.12.1",
"chrono",

View File

@ -18,3 +18,7 @@ members = [
[profile.release.build-override]
opt-level = 3
codegen-units = 16
[patch.crates-io]
spirv-std = { path = "./crates/spirv-std" }
glam = { git = "https://github.com/EmbarkStudios/glam-rs.git", branch ="spirv-std-impl" }

View File

@ -463,6 +463,9 @@ pub fn main() {
let vector = glam::Vec2::new(1.0, 2.0);
let element = unsafe { spirv_std::arch::vector_extract_dynamic(vector, 1) };
assert!(2.0 == element);
let uvector = glam::UVec2::new(1, 2);
let element: u32 = unsafe { spirv_std::arch::vector_extract_dynamic(uvector, 1) };
assert!(2 == element);
}
"#);
}
@ -476,6 +479,10 @@ pub fn main() {
let expected = glam::Vec2::new(1.0, 3.0);
let new_vector = unsafe { spirv_std::arch::vector_insert_dynamic(vector, 1, 3.0) };
assert!(new_vector == expected);
let uvector = glam::UVec2::new(1, 2);
let uexpected = glam::UVec2::new(1, 3);
let new_vector = unsafe { spirv_std::arch::vector_insert_dynamic(uvector, 1, 3) };
assert!(new_vector == uexpected);
}
"#);
}
@ -545,7 +552,7 @@ fn complex_image_sample_inst() {
}
#[spirv(fragment)]
pub fn main() {
sample_proj_lod(glam::Vec4::zero(), glam::Vec2::zero(), glam::Vec2::zero(), 0, 0);
sample_proj_lod(glam::Vec4::ZERO, glam::Vec2::ZERO, glam::Vec2::ZERO, 0, 0);
}"#,
"sample_proj_lod",
"%1 = OpFunction %2 None %3
@ -568,7 +575,7 @@ fn image_read() {
val(r#"
#[spirv(fragment)]
pub fn main(image: UniformConstant<StorageImage2d>, mut output: Output<glam::Vec2>) {
let coords = image.read(glam::IVec2::new(0, 1));
let coords = image.read(glam::IVec2::new(0, 1));
*output = coords;
}
"#);

View File

@ -330,7 +330,7 @@ fn issue_283() {
// version of issue 283 with loop uncommented and warnings fixed
// https://github.com/EmbarkStudios/rust-gpu/issues/283
val(r#"
use spirv_std::glam::*;
use glam::*;
fn sphere_sdf(p: Vec3) -> f32 {
p.length() - 1.0
}

View File

@ -47,7 +47,11 @@ overflow-checks = false
debug-assertions = false
[dependencies]
spirv-std = { path = "../../crates/spirv-std" }
spirv-std = { path = "../../crates/spirv-std", features=["const-generics"] }
glam = { git = "https://github.com/EmbarkStudios/glam-rs.git", branch="spirv-std-impl", default-features=false, features = ["libm", "scalar-math"] }
[patch.crates-io.spirv-std]
path="../../crates/spirv-std"
[workspace]
"#;

View File

@ -11,5 +11,6 @@ description = "Macros for spirv-std"
proc-macro = true
[dependencies]
proc-macro2 = "1.0.24"
quote = "1.0.8"
syn = { version = "1.0.58", features=["full"] }

View File

@ -47,11 +47,15 @@
// crate-specific exceptions:
#![allow()]
use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
use proc_macro::TokenStream;
use proc_macro2::{Delimiter, Group, Ident, Span, TokenTree};
use syn::{punctuated::Punctuated, spanned::Spanned, ItemFn, Token};
#[proc_macro_attribute]
pub fn spirv(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut tokens = Vec::new();
let item: proc_macro2::TokenStream = item.into();
for tt in item {
match tt {
TokenTree::Group(group) if group.delimiter() == Delimiter::Parenthesis => {
@ -60,7 +64,7 @@ pub fn spirv(_attr: TokenStream, item: TokenStream) -> TokenStream {
match tt {
TokenTree::Group(group)
if group.delimiter() == Delimiter::Bracket
&& matches!(group.stream().into_iter().next(), Some(TokenTree::Ident(ident)) if ident.to_string() == "spirv")
&& matches!(group.stream().into_iter().next(), Some(TokenTree::Ident(ident)) if ident == "spirv")
&& matches!(sub_tokens.last(), Some(TokenTree::Punct(p)) if p.as_char() == '#') =>
{
sub_tokens.pop();
@ -76,7 +80,10 @@ pub fn spirv(_attr: TokenStream, item: TokenStream) -> TokenStream {
_ => tokens.push(tt),
}
}
tokens.into_iter().collect()
tokens
.into_iter()
.collect::<proc_macro2::TokenStream>()
.into()
}
/// Marks a function as runnable only on the GPU, and will panic on
@ -105,3 +112,154 @@ pub fn gpu_only(_attr: TokenStream, item: TokenStream) -> TokenStream {
output.into()
}
/// Accepts a function with an argument named `component`, and outputs the
/// function plus a vectorized version of the function which accepts a vector
/// of `component`. This is mostly useful when you have the same impl body for
/// a scalar and vector versions of the same operation.
#[proc_macro_attribute]
#[doc(hidden)]
pub fn vectorized(_attr: TokenStream, item: TokenStream) -> TokenStream {
let function = syn::parse_macro_input!(item as syn::ItemFn);
let vectored_function = match create_vectored_fn(function.clone()) {
Ok(val) => val,
Err(err) => return err.to_compile_error().into(),
};
let output = quote::quote!(
#function
#vectored_function
);
output.into()
}
fn create_vectored_fn(
ItemFn {
mut attrs,
vis,
mut sig,
block,
}: ItemFn,
) -> Result<ItemFn, syn::Error> {
const COMPONENT_ARG_NAME: &str = "component";
let trait_bound_name = Ident::new("VECTOR", Span::mixed_site());
let const_bound_name = Ident::new("LENGTH", Span::mixed_site());
attrs.push(syn::Attribute {
pound_token: Default::default(),
style: syn::AttrStyle::Outer,
bracket_token: Default::default(),
path: Ident::new("cfg", Span::mixed_site()).into(),
tokens: quote::quote![(feature = "const-generics")],
});
sig.ident = Ident::new(&format!("{}_vector", sig.ident), Span::mixed_site());
sig.output = syn::ReturnType::Type(
Default::default(),
Box::new(path_from_ident(trait_bound_name.clone())),
);
let component_type = sig.inputs.iter_mut().find_map(|x| match x {
syn::FnArg::Typed(ty) => match &*ty.pat {
syn::Pat::Ident(pat) if pat.ident == COMPONENT_ARG_NAME => Some(&mut ty.ty),
_ => None,
},
_ => None,
});
if component_type.is_none() {
return Err(syn::Error::new(
sig.inputs.span(),
"#[vectorized] requires an argument named `component`.",
));
}
let component_type = component_type.unwrap();
let vector_path = {
let mut path = syn::Path {
leading_colon: None,
segments: Punctuated::new(),
};
for segment in &["crate", "vector"] {
path.segments
.push(Ident::new(segment, Span::mixed_site()).into());
}
path.segments.push(syn::PathSegment {
ident: Ident::new("Vector", Span::mixed_site()),
arguments: syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
colon2_token: None,
lt_token: Default::default(),
args: {
let mut punct = Punctuated::new();
punct.push(syn::GenericArgument::Type(*component_type.clone()));
punct.push(syn::GenericArgument::Type(path_from_ident(
const_bound_name.clone(),
)));
punct
},
gt_token: Default::default(),
}),
});
path
};
// Replace the original component type with vector version.
**component_type = path_from_ident(trait_bound_name.clone());
let trait_bounds = {
let mut punct = Punctuated::new();
punct.push(syn::TypeParamBound::Trait(syn::TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: vector_path,
}));
punct
};
sig.generics
.params
.push(syn::GenericParam::Type(syn::TypeParam {
attrs: Vec::new(),
ident: trait_bound_name,
colon_token: Some(Token![:](Span::mixed_site())),
bounds: trait_bounds,
eq_token: None,
default: None,
}));
sig.generics
.params
.push(syn::GenericParam::Const(syn::ConstParam {
attrs: Vec::default(),
const_token: Default::default(),
ident: const_bound_name,
colon_token: Default::default(),
ty: syn::Type::Path(syn::TypePath {
qself: None,
path: Ident::new("usize", Span::mixed_site()).into(),
}),
eq_token: None,
default: None,
}));
Ok(ItemFn {
attrs,
vis,
sig,
block,
})
}
fn path_from_ident(ident: Ident) -> syn::Type {
syn::Type::Path(syn::TypePath {
qself: None,
path: syn::Path::from(ident),
})
}

View File

@ -8,10 +8,9 @@ repository = "https://github.com/EmbarkStudios/rust-gpu"
description = "Standard functions and types for SPIR-V"
[dependencies]
glam = { version = "0.12.0", default-features = false, features = ["libm", "scalar-math"] }
num-traits = { version = "0.2.14", default-features = false }
num-traits = { version = "0.2.14", default-features = false, features = ["libm"] }
spirv-std-macros = { path = "../spirv-std-macros", version = "0.3.0" }
[features]
default = []
std = ["glam/std"]
const-generics = []

View File

@ -3,15 +3,19 @@
//! This module is intended as a low level abstraction over SPIR-V instructions.
//! These functions will typically map to a single instruction, and will perform
//! no additional safety checks beyond type-checking.
#[cfg(feature = "const-generics")]
use crate::{scalar::Scalar, vector::Vector};
mod derivative;
pub use derivative::*;
/// Result is true if any component of `vector` is true, otherwise result is
/// false.
#[spirv_std_macros::gpu_only]
#[doc(alias = "OpAny")]
#[inline]
// Remove after 25.03.2021 (Rust 1.51)
#[cfg(any())]
#[cfg(feature = "const-generics")]
pub fn any<V: Vector<bool, N>, const N: usize>(vector: V) -> bool {
let mut result = false;
@ -45,8 +49,7 @@ pub fn any<V: Vector<bool, N>, const N: usize>(vector: V) -> bool {
#[spirv_std_macros::gpu_only]
#[doc(alias = "OpAll")]
#[inline]
// Remove after 25.03.2021 (Rust 1.51)
#[cfg(any())]
#[cfg(feature = "const-generics")]
pub fn all<V: Vector<bool, N>, const N: usize>(vector: V) -> bool {
let mut result = false;
@ -83,7 +86,11 @@ pub fn all<V: Vector<bool, N>, const N: usize>(vector: V) -> bool {
#[spirv_std_macros::gpu_only]
#[doc(alias = "OpVectorExtractDynamic")]
#[inline]
pub unsafe fn vector_extract_dynamic<T: Scalar, V: Vector<T>>(vector: V, index: usize) -> T {
#[cfg(feature = "const-generics")]
pub unsafe fn vector_extract_dynamic<T: Scalar, const N: usize>(
vector: impl Vector<T, N>,
index: usize,
) -> T {
let mut result = T::default();
asm! {
@ -107,7 +114,8 @@ pub unsafe fn vector_extract_dynamic<T: Scalar, V: Vector<T>>(vector: V, index:
#[spirv_std_macros::gpu_only]
#[doc(alias = "OpVectorInsertDynamic")]
#[inline]
pub unsafe fn vector_insert_dynamic<T: Scalar, V: Vector<T>>(
#[cfg(feature = "const-generics")]
pub unsafe fn vector_insert_dynamic<T: Scalar, V: Vector<T, N>, const N: usize>(
vector: V,
index: usize,
element: T,

View File

@ -0,0 +1,115 @@
//! The [`Derivative`] trait for getting derivatives and handling derivative
//! operations in SPIR-V.
use crate::float::Float;
#[cfg(target_arch = "spirv")]
macro_rules! deriv_caps {
(true) => {
asm!("OpCapability DerivativeControl")
};
(false) => {};
}
#[cfg(target_arch = "spirv")]
macro_rules! deriv_fn {
($p:ident, $inst:ident, $needs_caps:tt) => {
unsafe {
let mut o = Default::default();
deriv_caps!($needs_caps);
asm!(
"%input = OpLoad _ {0}",
concat!("%result = ", stringify!($inst), " _ %input"),
"OpStore {1} %result",
in(reg) &$p,
in(reg) &mut o,
);
o
}
};
}
/// Returns the partial derivative of `Self` with respect to the window's
/// X coordinate. Returns the same result as either
/// [`Self::ddx_fine`] or [`Self::ddx_coarse`], selection of which one is
/// dependent on external factors.
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn ddx<F: Float>(component: F) -> F {
deriv_fn!(component, OpDPdx, false)
}
/// Returns the partial derivative of `Self` with respect to the window's
/// X coordinate. Uses local differencing based on the value of `Self` for
/// the current fragment and its immediate neighbor(s).
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn ddx_fine<F: Float>(component: F) -> F {
deriv_fn!(component, OpDPdxFine, true)
}
/// Returns the partial derivative of `Self` with respect to the window's
/// X coordinate. Uses local differencing based on the value of `Self` for
/// the current fragments neighbors, and possibly, but not necessarily,
/// includes the value of `Self` for the current fragment. That is, over a
/// given area, the implementation can compute X derivatives in fewer
/// unique locations than would be allowed by [`Self::ddx_fine`].
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn ddx_coarse<F: Float>(component: F) -> F {
deriv_fn!(component, OpDPdxCoarse, true)
}
/// Returns the partial derivative of `Self` with respect to the window's
/// Y coordinate. Returns the same result as either [`Self::ddy_fine`] or
/// [`Self::ddy_coarse`], selection of which one is dependent on
/// external factors.
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn ddy<F: Float>(component: F) -> F {
deriv_fn!(component, OpDPdy, false)
}
/// Returns the partial derivative of `Self` with respect to the window's
/// Y coordinate. Uses local differencing based on the value of `Self` for
/// the current fragment and its immediate neighbor(s).
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn ddy_fine<F: Float>(component: F) -> F {
deriv_fn!(component, OpDPdyFine, true)
}
/// Returns the partial derivative of `Self` with respect to the window's
/// Y coordinate. Uses local differencing based on the value of `Self` for
/// the current fragments neighbors, and possibly, but not necessarily,
/// includes the value of `Self` for the current fragment. That is, over a
/// given area, the implementation can compute Y derivatives in fewer
/// unique locations than would be allowed by [`Derivative::ddy_fine`].
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn ddy_coarse<F: Float>(component: F) -> F {
deriv_fn!(component, OpDPdyCoarse, true)
}
/// Returns the sum of the absolute values of [`Self::ddx`] and
/// [`Self::ddy`] as a single operation.
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn fwidth<F: Float>(component: F) -> F {
deriv_fn!(component, OpFwidth, false)
}
/// Returns the sum of the absolute values of [`Self::ddx_fine`] and
/// [`Self::ddy_fine`] as a single operation.
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn fwidth_fine<F: Float>(component: F) -> F {
deriv_fn!(component, OpFwidthFine, true)
}
/// Returns the sum of the absolute values of [`Self::ddx_coarse`] and
/// [`Self::ddy_coarse`] as a single operation.
#[spirv_std_macros::vectorized]
#[spirv_std_macros::gpu_only]
fn fwidth_coarse<F: Float>(component: F) -> F {
deriv_fn!(component, OpFwidthCoarse, true)
}

View File

@ -1,98 +0,0 @@
//! The [`Derivative`] trait for getting derivatives and handling derivative
//! operations in SPIR-V.
/// Represents a type that can represent the derivation of an operation.
pub trait Derivative {
/// Returns the partial derivative of `Self` with respect to the window's
/// X coordinate. Returns the same result as either
/// [`Self::ddx_fine`] or [`Self::ddx_coarse`], selection of which one is
/// dependent on external factors.
fn ddx(self) -> Self;
/// Returns the partial derivative of `Self` with respect to the window's
/// X coordinate. Uses local differencing based on the value of `Self` for
/// the current fragment and its immediate neighbor(s).
fn ddx_fine(self) -> Self;
/// Returns the partial derivative of `Self` with respect to the window's
/// X coordinate. Uses local differencing based on the value of `Self` for
/// the current fragments neighbors, and possibly, but not necessarily,
/// includes the value of `Self` for the current fragment. That is, over a
/// given area, the implementation can compute X derivatives in fewer
/// unique locations than would be allowed by [`Self::ddx_fine`].
fn ddx_coarse(self) -> Self;
/// Returns the partial derivative of `Self` with respect to the window's
/// Y coordinate. Returns the same result as either [`Self::ddy_fine`] or
/// [`Self::ddy_coarse`], selection of which one is dependent on
/// external factors.
fn ddy(self) -> Self;
/// Returns the partial derivative of `Self` with respect to the window's
/// Y coordinate. Uses local differencing based on the value of `Self` for
/// the current fragment and its immediate neighbor(s).
fn ddy_fine(self) -> Self;
/// Returns the partial derivative of `Self` with respect to the window's
/// Y coordinate. Uses local differencing based on the value of `Self` for
/// the current fragments neighbors, and possibly, but not necessarily,
/// includes the value of `Self` for the current fragment. That is, over a
/// given area, the implementation can compute Y derivatives in fewer
/// unique locations than would be allowed by [`Derivative::ddy_fine`].
fn ddy_coarse(self) -> Self;
/// Returns the sum of the absolute values of [`Self::ddx`] and
/// [`Self::ddy`] as a single operation.
fn fwidth(self) -> Self;
/// Returns the sum of the absolute values of [`Self::ddx_fine`] and
/// [`Self::ddy_fine`] as a single operation.
fn fwidth_fine(self) -> Self;
/// Returns the sum of the absolute values of [`Self::ddx_coarse`] and
/// [`Self::ddy_coarse`] as a single operation.
fn fwidth_coarse(self) -> Self;
}
#[cfg(target_arch = "spirv")]
macro_rules! deriv_caps {
(true) => {
asm!("OpCapability DerivativeControl")
};
(false) => {};
}
macro_rules! deriv_fn {
($name:ident, $inst:ident, $needs_caps:tt) => {
#[spirv_std_macros::gpu_only]
fn $name(self) -> Self {
unsafe {
let mut o = Default::default();
deriv_caps!($needs_caps);
asm!(
"%input = OpLoad _ {0}",
concat!("%result = ", stringify!($inst), " _ %input"),
"OpStore {1} %result",
in(reg) &self,
in(reg) &mut o,
);
o
}
}
};
}
macro_rules! deriv_impl {
($ty:ty) => {
impl Derivative for $ty {
deriv_fn!(ddx, OpDPdx, false);
deriv_fn!(ddx_fine, OpDPdxFine, true);
deriv_fn!(ddx_coarse, OpDPdxCoarse, true);
deriv_fn!(ddy, OpDPdy, false);
deriv_fn!(ddy_fine, OpDPdyFine, true);
deriv_fn!(ddy_coarse, OpDPdyCoarse, true);
deriv_fn!(fwidth, OpFwidth, false);
deriv_fn!(fwidth_fine, OpFwidthFine, true);
deriv_fn!(fwidth_coarse, OpFwidthCoarse, true);
}
};
}
// "must be a scalar or vector of floating-point type. The component width must be 32 bits."
deriv_impl!(f32);
deriv_impl!(glam::Vec2);
deriv_impl!(glam::Vec3);
deriv_impl!(glam::Vec3A);
deriv_impl!(glam::Vec4);

View File

@ -0,0 +1,12 @@
/// Abstract trait representing a SPIR-V floating point type.
pub unsafe trait Float: num_traits::Float + crate::scalar::Scalar + Default {
const WIDTH: usize;
}
unsafe impl Float for f32 {
const WIDTH: usize = 32;
}
unsafe impl Float for f64 {
const WIDTH: usize = 64;
}

View File

@ -1,11 +1,11 @@
/// Abstract trait representing a SPIR-V integer type.
pub trait Integer: num_traits::PrimInt + crate::scalar::Scalar {}
pub unsafe trait Integer: num_traits::PrimInt + crate::scalar::Scalar {}
impl Integer for u8 {}
impl Integer for u16 {}
impl Integer for u32 {}
impl Integer for u64 {}
impl Integer for i8 {}
impl Integer for i16 {}
impl Integer for i32 {}
impl Integer for i64 {}
unsafe impl Integer for u8 {}
unsafe impl Integer for u16 {}
unsafe impl Integer for u32 {}
unsafe impl Integer for u64 {}
unsafe impl Integer for i8 {}
unsafe impl Integer for i16 {}
unsafe impl Integer for i32 {}
unsafe impl Integer for i64 {}

View File

@ -65,12 +65,12 @@
clippy::unimplemented,
)]
#[cfg(not(target_arch = "spirv"))]
#[macro_use]
pub extern crate spirv_std_macros;
#[cfg(not(target_arch = "spirv"))]
pub extern crate spirv_std_macros as macros;
pub mod arch;
pub mod derivative;
pub mod float;
pub mod integer;
pub mod scalar;
pub(crate) mod sealed;
@ -78,7 +78,6 @@ pub mod storage_class;
mod textures;
pub mod vector;
pub use glam;
pub use num_traits;
pub use textures::*;

View File

@ -1,13 +1,14 @@
/// Abstract trait representing a SPIR-V scalar type.
pub trait Scalar: Copy + Default + crate::sealed::Sealed {}
pub unsafe trait Scalar: Copy + Default + crate::sealed::Sealed {}
impl Scalar for bool {}
impl Scalar for f32 {}
impl Scalar for u8 {}
impl Scalar for u16 {}
impl Scalar for u32 {}
impl Scalar for u64 {}
impl Scalar for i8 {}
impl Scalar for i16 {}
impl Scalar for i32 {}
impl Scalar for i64 {}
unsafe impl Scalar for bool {}
unsafe impl Scalar for f32 {}
unsafe impl Scalar for f64 {}
unsafe impl Scalar for u8 {}
unsafe impl Scalar for u16 {}
unsafe impl Scalar for u32 {}
unsafe impl Scalar for u64 {}
unsafe impl Scalar for i8 {}
unsafe impl Scalar for i16 {}
unsafe impl Scalar for i32 {}
unsafe impl Scalar for i64 {}

View File

@ -4,6 +4,7 @@ pub trait Sealed {}
impl Sealed for bool {}
impl Sealed for f32 {}
impl Sealed for f64 {}
impl Sealed for u8 {}
impl Sealed for u16 {}
impl Sealed for u32 {}
@ -12,16 +13,3 @@ impl Sealed for i8 {}
impl Sealed for i16 {}
impl Sealed for i32 {}
impl Sealed for i64 {}
impl Sealed for glam::BVec2 {}
impl Sealed for glam::BVec3 {}
impl Sealed for glam::BVec4 {}
impl Sealed for glam::Vec2 {}
impl Sealed for glam::Vec3 {}
impl Sealed for glam::Vec3A {}
impl Sealed for glam::Vec4 {}
impl Sealed for glam::UVec2 {}
impl Sealed for glam::UVec3 {}
impl Sealed for glam::UVec4 {}
impl Sealed for glam::IVec2 {}
impl Sealed for glam::IVec3 {}
impl Sealed for glam::IVec4 {}

View File

@ -1,5 +1,4 @@
use glam::{Vec2, Vec3A, Vec4};
#[cfg(feature = "const-generics")]
use crate::{integer::Integer, vector::Vector};
#[spirv(sampler)]
@ -24,7 +23,12 @@ pub struct Image2d {
impl Image2d {
#[spirv_std_macros::gpu_only]
pub fn sample(&self, sampler: Sampler, coordinate: Vec2) -> Vec4 {
#[cfg(feature = "const-generics")]
pub fn sample<V: Vector<f32, 4>>(
&self,
sampler: Sampler,
coordinate: impl Vector<f32, 2>,
) -> V {
unsafe {
let mut result = Default::default();
asm!(
@ -44,11 +48,13 @@ impl Image2d {
}
/// Fetch a single texel with a sampler set at compile time
#[spirv_std_macros::gpu_only]
pub fn fetch<I>(&self, coordinate: impl Vector<I>) -> Vec4
#[cfg(feature = "const-generics")]
pub fn fetch<V, I, const N: usize>(&self, coordinate: impl Vector<I, N>) -> V
where
V: Vector<f32, 4>,
I: Integer,
{
let mut result = Vec4::default();
let mut result = V::default();
unsafe {
asm! {
"%image = OpLoad _ {this}",
@ -82,13 +88,13 @@ pub struct StorageImage2d {
impl StorageImage2d {
/// Read a texel from an image without a sampler.
#[spirv_std_macros::gpu_only]
pub fn read<I, V, V2>(&self, coordinate: V) -> V2
#[cfg(feature = "const-generics")]
pub fn read<I, V, const N: usize>(&self, coordinate: impl Vector<I, 2>) -> V
where
I: Integer,
V: Vector<I>,
V2: Vector<f32>,
V: Vector<f32, N>,
{
let mut result = V2::default();
let mut result = V::default();
unsafe {
asm! {
@ -107,11 +113,13 @@ impl StorageImage2d {
/// Write a texel to an image without a sampler.
#[spirv_std_macros::gpu_only]
pub unsafe fn write<I, V, V2>(&self, coordinate: V, texels: V2)
where
#[cfg(feature = "const-generics")]
pub unsafe fn write<I, const N: usize>(
&self,
coordinate: impl Vector<I, 2>,
texels: impl Vector<f32, N>,
) where
I: Integer,
V: Vector<I>,
V2: Vector<f32>,
{
asm! {
"%image = OpLoad _ {this}",
@ -141,9 +149,14 @@ pub struct Image2dArray {
impl Image2dArray {
#[spirv_std_macros::gpu_only]
pub fn sample(&self, sampler: Sampler, coordinate: Vec3A) -> Vec4 {
#[cfg(feature = "const-generics")]
pub fn sample<V: Vector<f32, 4>>(
&self,
sampler: Sampler,
coordinate: impl Vector<f32, 3>,
) -> V {
unsafe {
let mut result = Default::default();
let mut result = V::default();
asm!(
"%image = OpLoad _ {this}",
"%sampler = OpLoad _ {sampler}",
@ -169,7 +182,8 @@ pub struct SampledImage<I> {
impl SampledImage<Image2d> {
#[spirv_std_macros::gpu_only]
pub fn sample(&self, coordinate: Vec2) -> Vec4 {
#[cfg(feature = "const-generics")]
pub fn sample<V: Vector<f32, 4>>(&self, coordinate: impl Vector<f32, 2>) -> V {
unsafe {
let mut result = Default::default();
asm!(

View File

@ -1,16 +1,3 @@
/// Abstract trait representing a SPIR-V vector type.
pub trait Vector<T: crate::scalar::Scalar>: crate::sealed::Sealed + Default {}
impl Vector<bool> for glam::BVec2 {}
impl Vector<bool> for glam::BVec3 {}
impl Vector<bool> for glam::BVec4 {}
impl Vector<f32> for glam::Vec2 {}
impl Vector<f32> for glam::Vec3 {}
impl Vector<f32> for glam::Vec3A {}
impl Vector<f32> for glam::Vec4 {}
impl Vector<u32> for glam::UVec2 {}
impl Vector<u32> for glam::UVec3 {}
impl Vector<u32> for glam::UVec4 {}
impl Vector<i32> for glam::IVec2 {}
impl Vector<i32> for glam::IVec3 {}
impl Vector<i32> for glam::IVec4 {}
#[cfg(feature = "const-generics")]
pub unsafe trait Vector<T: crate::scalar::Scalar, const N: usize>: Default {}

View File

@ -11,7 +11,7 @@ minifb = "0.19.2"
# bring in the shader as natively compiled code
shared = { path = "../../shaders/shared" }
sky-shader = { path = "../../shaders/sky-shader" }
spirv-std = { path = "../../../crates/spirv-std", features = ["std"] }
spirv-std = { path = "../../../crates/spirv-std" }
# for parallelism, not really needed though
rayon = "1.5"

View File

@ -44,8 +44,8 @@
use minifb::{Key, Window, WindowOptions};
use rayon::prelude::*;
use shared::glam::{vec2, Vec2, Vec4};
use shared::ShaderConstants;
use spirv_std::glam::{vec2, Vec2, Vec4};
use std::time::Instant;
use sky_shader as shader_module;
@ -109,7 +109,7 @@ fn main() {
-((i / WIDTH) as f32 / HEIGHT as f32 * 2.0 - 1.0),
);
let frag_coord = (vec2(screen_pos.x, -screen_pos.y) + Vec2::one()) / Vec2::splat(2.0)
let frag_coord = (vec2(screen_pos.x, -screen_pos.y) + Vec2::ONE) / Vec2::splat(2.0)
* vec2(WIDTH as f32, HEIGHT as f32);
// evaluate the fragment shader for the specific pixel

View File

@ -8,8 +8,8 @@
#![deny(warnings)]
use core::f32::consts::PI;
use glam::{const_vec4, vec2, vec3, Mat2, Vec2, Vec3, Vec4, Vec4Swizzles};
use shared::*;
use spirv_std::glam::{const_vec4, vec2, vec3, Mat2, Vec2, Vec3, Vec4, Vec4Swizzles};
use spirv_std::storage_class::{Input, Output, PushConstant};
// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but
@ -18,7 +18,7 @@ use spirv_std::storage_class::{Input, Output, PushConstant};
use spirv_std::num_traits::Float;
#[cfg(not(target_arch = "spirv"))]
use spirv_std::spirv_std_macros::spirv;
use spirv_std::macros::spirv;
trait Shape: Copy {
/// Distances indicate where the point is in relation to the shape:
@ -138,10 +138,7 @@ impl Painter {
/// Fill and add a constrasting border (0.5px thick stroke of inverted color).
fn fill_with_contrast_border(&mut self, shape: impl Shape, color: Vec4) {
self.fill(shape, color);
self.fill(
shape.stroke(0.5),
(Vec3::one() - color.xyz()).extend(color.w),
);
self.fill(shape.stroke(0.5), (Vec3::ONE - color.xyz()).extend(color.w));
}
}
@ -267,7 +264,7 @@ pub fn main_vs(
// Create a "full screen triangle" by mapping the vertex index.
// ported from https://www.saschawillems.de/blog/2016/08/13/vulkan-tutorial-on-rendering-a-fullscreen-quad-without-buffers/
let uv = vec2(((vert_idx << 1) & 2) as f32, (vert_idx & 2) as f32);
let pos = 2.0 * uv - Vec2::one();
let pos = 2.0 * uv - Vec2::ONE;
*builtin_pos = pos.extend(0.0).extend(1.0);
}

View File

@ -9,3 +9,4 @@ publish = false
[dependencies]
spirv-std-macros = { path = "../../../crates/spirv-std-macros" }
spirv-std = { path = "../../../crates/spirv-std" }
glam = { version = "0.13", default-features = false, features = ["libm", "scalar-math"] }

View File

@ -12,7 +12,9 @@
pub extern crate spirv_std_macros;
use core::f32::consts::PI;
use spirv_std::glam::{vec3, Vec3};
use glam::{vec3, Vec3};
pub use glam;
// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but
// we tie #[no_std] above to the same condition, so it's fine.

View File

@ -12,3 +12,4 @@ crate-type = ["dylib"]
[dependencies]
spirv-std-macros = { path = "../../../crates/spirv-std-macros" }
spirv-std = { path = "../../../crates/spirv-std" }
shared = { path = "../shared" }

View File

@ -10,7 +10,7 @@
#[cfg(not(target_arch = "spirv"))]
#[macro_use]
pub extern crate spirv_std_macros;
use spirv_std::glam::{vec4, Vec4};
use shared::glam::{vec4, Vec4};
use spirv_std::storage_class::{Input, Output};
#[spirv(fragment)]

View File

@ -14,8 +14,8 @@
pub extern crate spirv_std_macros;
use core::f32::consts::PI;
use glam::{const_vec3, vec2, vec3, Vec2, Vec3, Vec4};
use shared::*;
use spirv_std::glam::{const_vec3, vec2, vec3, Vec2, Vec3, Vec4};
use spirv_std::storage_class::{Input, Output, PushConstant};
// Note: This cfg is incorrect on its surface, it really should be "are we compiling with std", but
@ -178,7 +178,7 @@ pub fn main_vs(
// Create a "full screen triangle" by mapping the vertex index.
// ported from https://www.saschawillems.de/blog/2016/08/13/vulkan-tutorial-on-rendering-a-fullscreen-quad-without-buffers/
let uv = vec2(((vert_idx << 1) & 2) as f32, (vert_idx & 2) as f32);
let pos = 2.0 * uv - Vec2::one();
let pos = 2.0 * uv - Vec2::ONE;
*builtin_pos = pos.extend(0.0).extend(1.0);
}