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 {}