|
| 1 | +#![no_std] |
| 2 | +#![feature(register_attr, repr_simd, core_intrinsics)] |
| 3 | +#![cfg_attr(target_arch = "spirv", feature(asm))] |
| 4 | +#![register_attr(spirv)] |
| 5 | +// Our standard Clippy lints that we use in Embark projects, we opt out of a few that are not appropriate for the specific crate (yet) |
| 6 | +#![warn( |
| 7 | + clippy::all, |
| 8 | + clippy::doc_markdown, |
| 9 | + clippy::dbg_macro, |
| 10 | + clippy::todo, |
| 11 | + clippy::empty_enum, |
| 12 | + clippy::enum_glob_use, |
| 13 | + clippy::pub_enum_variant_names, |
| 14 | + clippy::mem_forget, |
| 15 | + clippy::filter_map_next, |
| 16 | + clippy::needless_continue, |
| 17 | + clippy::needless_borrow, |
| 18 | + clippy::match_wildcard_for_single_variants, |
| 19 | + clippy::if_let_mutex, |
| 20 | + clippy::mismatched_target_os, |
| 21 | + clippy::await_holding_lock, |
| 22 | + clippy::match_on_vec_items, |
| 23 | + clippy::imprecise_flops, |
| 24 | + //clippy::suboptimal_flops, |
| 25 | + clippy::lossy_float_literal, |
| 26 | + clippy::rest_pat_in_fully_bound_structs, |
| 27 | + clippy::fn_params_excessive_bools, |
| 28 | + clippy::exit, |
| 29 | + clippy::inefficient_to_string, |
| 30 | + clippy::linkedlist, |
| 31 | + clippy::macro_use_imports, |
| 32 | + clippy::option_option, |
| 33 | + clippy::verbose_file_reads, |
| 34 | + clippy::unnested_or_patterns, |
| 35 | + rust_2018_idioms, |
| 36 | + future_incompatible, |
| 37 | + nonstandard_style |
| 38 | +)] |
| 39 | + |
| 40 | +mod math_ext; |
| 41 | +pub use math_ext::MathExt; |
| 42 | + |
| 43 | +pub use glam; |
| 44 | + |
| 45 | +macro_rules! pointer_addrspace_write { |
| 46 | + (false) => {}; |
| 47 | + (true) => { |
| 48 | + #[inline] |
| 49 | + #[allow(unused_attributes)] |
| 50 | + #[spirv(really_unsafe_ignore_bitcasts)] |
| 51 | + pub fn store(&mut self, v: T) { |
| 52 | + *self.x = v |
| 53 | + } |
| 54 | + }; |
| 55 | +} |
| 56 | + |
| 57 | +macro_rules! pointer_addrspace { |
| 58 | + ($storage_class:ident, $type_name:ident, $writeable:tt) => { |
| 59 | + #[allow(unused_attributes)] |
| 60 | + #[spirv($storage_class)] |
| 61 | + pub struct $type_name<'a, T> { |
| 62 | + x: &'a mut T, |
| 63 | + } |
| 64 | + |
| 65 | + impl<'a, T: Copy> $type_name<'a, T> { |
| 66 | + #[inline] |
| 67 | + #[allow(unused_attributes)] |
| 68 | + #[spirv(really_unsafe_ignore_bitcasts)] |
| 69 | + pub fn load(&self) -> T { |
| 70 | + *self.x |
| 71 | + } |
| 72 | + |
| 73 | + pointer_addrspace_write!($writeable); |
| 74 | + } |
| 75 | + }; |
| 76 | +} |
| 77 | + |
| 78 | +// Make sure these strings stay synced with symbols.rs |
| 79 | +// Note the type names don't have to match anything, they can be renamed (only the string must match) |
| 80 | +pointer_addrspace!(uniform_constant, UniformConstant, false); |
| 81 | +pointer_addrspace!(input, Input, false); |
| 82 | +pointer_addrspace!(uniform, Uniform, true); |
| 83 | +pointer_addrspace!(output, Output, true); |
| 84 | +pointer_addrspace!(workgroup, Workgroup, true); |
| 85 | +pointer_addrspace!(cross_workgroup, CrossWorkgroup, true); |
| 86 | +pointer_addrspace!(private, Private, true); |
| 87 | +pointer_addrspace!(function, Function, true); |
| 88 | +pointer_addrspace!(generic, Generic, true); |
| 89 | +pointer_addrspace!(push_constant, PushConstant, false); |
| 90 | +pointer_addrspace!(atomic_counter, AtomicCounter, true); |
| 91 | +pointer_addrspace!(image, Image, true); |
| 92 | +pointer_addrspace!(storage_buffer, StorageBuffer, true); |
| 93 | +pointer_addrspace!(callable_data_khr, CallableDataKHR, true); |
| 94 | +pointer_addrspace!(incoming_callable_data_khr, IncomingCallableDataKHR, true); |
| 95 | +pointer_addrspace!(ray_payload_khr, RayPayloadKHR, true); |
| 96 | +pointer_addrspace!(hit_attribute_khr, HitAttributeKHR, true); |
| 97 | +pointer_addrspace!(incoming_ray_payload_khr, IncomingRayPayloadKHR, true); |
| 98 | +pointer_addrspace!(shader_record_buffer_khr, ShaderRecordBufferKHR, true); |
| 99 | +pointer_addrspace!(physical_storage_buffer, PhysicalStorageBuffer, true); |
| 100 | + |
| 101 | +pub trait Derivative { |
| 102 | + fn ddx(self) -> Self; |
| 103 | + fn ddx_fine(self) -> Self; |
| 104 | + fn ddx_coarse(self) -> Self; |
| 105 | + fn ddy(self) -> Self; |
| 106 | + fn ddy_fine(self) -> Self; |
| 107 | + fn ddy_coarse(self) -> Self; |
| 108 | + fn fwidth(self) -> Self; |
| 109 | + fn fwidth_fine(self) -> Self; |
| 110 | + fn fwidth_coarse(self) -> Self; |
| 111 | +} |
| 112 | + |
| 113 | +#[cfg(target_arch = "spirv")] |
| 114 | +macro_rules! deriv_caps { |
| 115 | + (true) => { |
| 116 | + asm!("OpCapability DerivativeControl") |
| 117 | + }; |
| 118 | + (false) => {}; |
| 119 | +} |
| 120 | + |
| 121 | +macro_rules! deriv_fn { |
| 122 | + ($name:ident, $inst:ident, $needs_caps:tt) => { |
| 123 | + fn $name(self) -> Self { |
| 124 | + #[cfg(not(target_arch = "spirv"))] |
| 125 | + panic!(concat!(stringify!($name), " is not supported on the CPU")); |
| 126 | + #[cfg(target_arch = "spirv")] |
| 127 | + unsafe { |
| 128 | + let o; |
| 129 | + deriv_caps!($needs_caps); |
| 130 | + asm!( |
| 131 | + concat!("{1} = ", stringify!($inst), " typeof{0} {0}"), |
| 132 | + in(reg) self, |
| 133 | + out(reg) o, |
| 134 | + ); |
| 135 | + o |
| 136 | + } |
| 137 | + } |
| 138 | + }; |
| 139 | +} |
| 140 | +macro_rules! deriv_impl { |
| 141 | + ($ty:ty) => { |
| 142 | + impl Derivative for $ty { |
| 143 | + deriv_fn!(ddx, OpDPdx, false); |
| 144 | + deriv_fn!(ddx_fine, OpDPdxFine, true); |
| 145 | + deriv_fn!(ddx_coarse, OpDPdxCoarse, true); |
| 146 | + deriv_fn!(ddy, OpDPdy, false); |
| 147 | + deriv_fn!(ddy_fine, OpDPdyFine, true); |
| 148 | + deriv_fn!(ddy_coarse, OpDPdyCoarse, true); |
| 149 | + deriv_fn!(fwidth, OpFwidth, false); |
| 150 | + deriv_fn!(fwidth_fine, OpFwidthFine, true); |
| 151 | + deriv_fn!(fwidth_coarse, OpFwidthCoarse, true); |
| 152 | + } |
| 153 | + }; |
| 154 | +} |
| 155 | + |
| 156 | +// "must be a scalar or vector of floating-point type. The component width must be 32 bits." |
| 157 | +deriv_impl!(f32); |
| 158 | +// TODO: Fix rustc to support these |
| 159 | +// deriv_impl!(glam::Vec2); |
| 160 | +// deriv_impl!(glam::Vec3); |
| 161 | +// deriv_impl!(glam::Vec4); |
| 162 | + |
| 163 | +/// libcore requires a few external symbols to be defined: |
| 164 | +/// <https://github.com/rust-lang/rust/blob/c2bc344eb23d8c1d18e803b3f1e631cf99926fbb/library/core/src/lib.rs#L23-L27> |
| 165 | +/// TODO: This is copied from `compiler_builtins/mem.rs`. Can we use that one instead? The note in the above link says |
| 166 | +/// "[the symbols] can also be provided by the compiler-builtins crate". The memcpy in `compiler_builtins` is behind a |
| 167 | +/// "mem" feature flag - can we enable that somehow? |
| 168 | +/// <https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/src/mem.rs#L12-L13> |
| 169 | +#[allow(clippy::missing_safety_doc)] |
| 170 | +#[no_mangle] |
| 171 | +pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { |
| 172 | + let mut i = 0; |
| 173 | + while i < n { |
| 174 | + let a = *s1.add(i); |
| 175 | + let b = *s2.add(i); |
| 176 | + if a != b { |
| 177 | + return a as i32 - b as i32; |
| 178 | + } |
| 179 | + i += 1; |
| 180 | + } |
| 181 | + 0 |
| 182 | +} |
0 commit comments