spirv_std/arch/derivative.rs
1use crate::sealed::Sealed;
2use glam::{Vec2, Vec3, Vec3A, Vec4};
3
4#[cfg(target_arch = "spirv")]
5macro_rules! deriv_fn {
6 ($inst:ident, $param:expr) => {
7 unsafe {
8 let mut result = Default::default();
9 core::arch::asm!(
10 "%input = OpLoad typeof*{1} {1}",
11 concat!("%result = ", stringify!($inst), " typeof*{1} %input"),
12 "OpStore {0} %result",
13 in(reg) &mut result,
14 in(reg) &$param,
15 );
16 result
17 }
18 };
19}
20
21/// Types that can be derived by partial derivatives
22///
23/// # Safety
24/// Result Type must be a scalar or vector of floating-point type using the IEEE 754 encoding. The component width must be 32 bits.
25pub unsafe trait Derivative: Sealed + Default {
26 /// Result is the partial derivative of `Self` with respect to the window x coordinate. Uses local differencing
27 /// based on the value of `Self`. Same result as either [`Self::dfdx_fine`] or [`Self::dfdx_coarse`] on `Self`. Selection of which
28 /// one is based on external factors.
29 ///
30 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
31 /// derivative group have executed all dynamic instances that are program-ordered before X'.
32 ///
33 /// This instruction is only valid in the Fragment Execution Model.
34 #[crate::macros::gpu_only]
35 #[inline]
36 fn dfdx(self) -> Self {
37 deriv_fn!(OpDPdx, self)
38 }
39
40 /// Result is the partial derivative of `Self` with respect to the window x coordinate. Uses local differencing
41 /// based on the value of `Self` for the current fragment and its immediate neighbor(s).
42 ///
43 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
44 /// derivative group have executed all dynamic instances that are program-ordered before X'.
45 ///
46 /// This instruction is only valid in the Fragment Execution Model.
47 #[crate::macros::gpu_only]
48 #[inline]
49 fn dfdx_fine(self) -> Self {
50 deriv_fn!(OpDPdxFine, self)
51 }
52
53 /// Result is the partial derivative of `Self` with respect to the window x coordinate. Uses local differencing
54 /// based on the value of `Self` for the current fragment’s neighbors, and possibly, but not necessarily, includes
55 /// the value of `Self` for the current fragment. That is, over a given area, the implementation can compute x
56 /// derivatives in fewer unique locations than would be allowed for [`Self::dfdx_fine`].
57 ///
58 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
59 /// derivative group have executed all dynamic instances that are program-ordered before X'.
60 ///
61 /// This instruction is only valid in the Fragment Execution Model.
62 #[crate::macros::gpu_only]
63 #[inline]
64 fn dfdx_coarse(self) -> Self {
65 deriv_fn!(OpDPdxCoarse, self)
66 }
67
68 /// Result is the partial derivative of `Self` with respect to the window y coordinate. Uses local differencing
69 /// based on the value of `Self`. Same result as either [`Self::dfdy_fine`] or [`Self::dfdy_coarse`] on `Self`. Selection of which
70 /// one is based on external factors.
71 ///
72 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
73 /// derivative group have executed all dynamic instances that are program-ordered before X'.
74 ///
75 /// This instruction is only valid in the Fragment Execution Model.
76 #[crate::macros::gpu_only]
77 #[inline]
78 fn dfdy(self) -> Self {
79 deriv_fn!(OpDPdy, self)
80 }
81
82 /// Result is the partial derivative of `Self` with respect to the window y coordinate. Uses local differencing
83 /// based on the value of `Self` for the current fragment and its immediate neighbor(s).
84 ///
85 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
86 /// derivative group have executed all dynamic instances that are program-ordered before X'.
87 ///
88 /// This instruction is only valid in the Fragment Execution Model.
89 #[crate::macros::gpu_only]
90 #[inline]
91 fn dfdy_fine(self) -> Self {
92 deriv_fn!(OpDPdyFine, self)
93 }
94
95 /// Result is the partial derivative of `Self` with respect to the window y coordinate. Uses local differencing
96 /// based on the value of `Self` for the current fragment’s neighbors, and possibly, but not necessarily, includes
97 /// the value of `Self` for the current fragment. That is, over a given area, the implementation can compute y
98 /// derivatives in fewer unique locations than would be allowed for [`Self::dfdy_fine`].
99 ///
100 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
101 /// derivative group have executed all dynamic instances that are program-ordered before X'.
102 ///
103 /// This instruction is only valid in the Fragment Execution Model.
104 #[crate::macros::gpu_only]
105 #[inline]
106 fn dfdy_coarse(self) -> Self {
107 deriv_fn!(OpDPdyCoarse, self)
108 }
109
110 /// Result is the same as computing the sum of the absolute values of [`Self::dfdx`] and [`Self::dfdy`] on P.
111 ///
112 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
113 /// derivative group have executed all dynamic instances that are program-ordered before X'.
114 ///
115 /// This instruction is only valid in the Fragment Execution Model.
116 #[crate::macros::gpu_only]
117 #[inline]
118 fn fwidth(self) -> Self {
119 deriv_fn!(OpFwidth, self)
120 }
121
122 /// Result is the same as computing the sum of the absolute values of [`Self::dfdx_fine`] and [`Self::dfdy_fine`] on P.
123 ///
124 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
125 /// derivative group have executed all dynamic instances that are program-ordered before X'.
126 ///
127 /// This instruction is only valid in the Fragment Execution Model.
128 #[crate::macros::gpu_only]
129 #[inline]
130 fn fwidth_fine(self) -> Self {
131 deriv_fn!(OpFwidthFine, self)
132 }
133
134 /// Result is the same as computing the sum of the absolute values of [`Self::dfdx_coarse`] and [`Self::dfdy_coarse`] on P.
135 ///
136 /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
137 /// derivative group have executed all dynamic instances that are program-ordered before X'.
138 ///
139 /// This instruction is only valid in the Fragment Execution Model.
140 #[crate::macros::gpu_only]
141 #[inline]
142 fn fwidth_coarse(self) -> Self {
143 deriv_fn!(OpFwidthCoarse, self)
144 }
145}
146
147unsafe impl Derivative for f32 {}
148unsafe impl Derivative for Vec2 {}
149unsafe impl Derivative for Vec3 {}
150unsafe impl Derivative for Vec4 {}
151unsafe impl Derivative for Vec3A {}