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