spirv_std/arch/
derivative.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use crate::sealed::Sealed;
use glam::{Vec2, Vec3, Vec3A, Vec4};

#[cfg(target_arch = "spirv")]
macro_rules! deriv_fn {
    ($inst:ident, $param:expr) => {
        unsafe {
            let mut result = Default::default();
            core::arch::asm!(
                "%input = OpLoad typeof*{1} {1}",
                concat!("%result = ", stringify!($inst), " typeof*{1} %input"),
                "OpStore {0} %result",
                in(reg) &mut result,
                in(reg) &$param,
            );
            result
        }
    };
}

/// Types that can be derived by partial derivatives
///
/// # Safety
/// Result Type must be a scalar or vector of floating-point type using the IEEE 754 encoding. The component width must be 32 bits.
pub unsafe trait Derivative: Sealed + Default {
    /// Result is the partial derivative of `Self` with respect to the window x coordinate. Uses local differencing
    /// based on the value of `Self`. Same result as either [`Self::dfdx_fine`] or [`Self::dfdx_coarse`] on `Self`. Selection of which
    /// one is based on external factors.
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn dfdx(self) -> Self {
        deriv_fn!(OpDPdx, self)
    }

    /// Result is the partial derivative of `Self` with respect to the window x coordinate. Uses local differencing
    /// based on the value of `Self` for the current fragment and its immediate neighbor(s).
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn dfdx_fine(self) -> Self {
        deriv_fn!(OpDPdxFine, self)
    }

    /// Result is the partial derivative of `Self` with respect to the window x coordinate. Uses local differencing
    /// based on the value of `Self` for the current fragment’s 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 for [`Self::dfdx_fine`].
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn dfdx_coarse(self) -> Self {
        deriv_fn!(OpDPdxCoarse, self)
    }

    /// Result is the partial derivative of `Self` with respect to the window y coordinate. Uses local differencing
    /// based on the value of `Self`. Same result as either [`Self::dfdy_fine`] or [`Self::dfdy_coarse`] on `Self`. Selection of which
    /// one is based on external factors.
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn dfdy(self) -> Self {
        deriv_fn!(OpDPdy, self)
    }

    /// Result is the partial derivative of `Self` with respect to the window y coordinate. Uses local differencing
    /// based on the value of `Self` for the current fragment and its immediate neighbor(s).
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn dfdy_fine(self) -> Self {
        deriv_fn!(OpDPdyFine, self)
    }

    /// Result is the partial derivative of `Self` with respect to the window y coordinate. Uses local differencing
    /// based on the value of `Self` for the current fragment’s 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 for [`Self::dfdy_fine`].
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn dfdy_coarse(self) -> Self {
        deriv_fn!(OpDPdyCoarse, self)
    }

    /// Result is the same as computing the sum of the absolute values of [`Self::dfdx`] and [`Self::dfdy`] on P.
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn fwidth(self) -> Self {
        deriv_fn!(OpFwidth, self)
    }

    /// Result is the same as computing the sum of the absolute values of [`Self::dfdx_fine`] and [`Self::dfdy_fine`] on P.
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn fwidth_fine(self) -> Self {
        deriv_fn!(OpFwidthFine, self)
    }

    /// Result is the same as computing the sum of the absolute values of [`Self::dfdx_coarse`] and [`Self::dfdy_coarse`] on P.
    ///
    /// An invocation will not execute a dynamic instance of this instruction (X') until all invocations in its
    /// derivative group have executed all dynamic instances that are program-ordered before X'.
    ///
    /// This instruction is only valid in the Fragment Execution Model.
    #[crate::macros::gpu_only]
    #[inline]
    fn fwidth_coarse(self) -> Self {
        deriv_fn!(OpFwidthCoarse, self)
    }
}

unsafe impl Derivative for f32 {}
unsafe impl Derivative for Vec2 {}
unsafe impl Derivative for Vec3 {}
unsafe impl Derivative for Vec4 {}
unsafe impl Derivative for Vec3A {}