1 //===----- hlsl_intrinsic_helpers.h - HLSL helpers intrinsics -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef _HLSL_HLSL_INTRINSIC_HELPERS_H_
10 #define _HLSL_HLSL_INTRINSIC_HELPERS_H_
11
12 namespace hlsl {
13 namespace __detail {
14
d3d_color_to_ubyte4_impl(vector<float,4> V)15 constexpr vector<uint, 4> d3d_color_to_ubyte4_impl(vector<float, 4> V) {
16 // Use the same scaling factor used by FXC, and DXC for DXIL
17 // (i.e., 255.001953)
18 // https://github.com/microsoft/DirectXShaderCompiler/blob/070d0d5a2beacef9eeb51037a9b04665716fd6f3/lib/HLSL/HLOperationLower.cpp#L666C1-L697C2
19 // The DXC implementation refers to a comment on the following stackoverflow
20 // discussion to justify the scaling factor: "Built-in rounding, necessary
21 // because of truncation. 0.001953 * 256 = 0.5"
22 // https://stackoverflow.com/questions/52103720/why-does-d3dcolortoubyte4-multiplies-components-by-255-001953f
23 return V.zyxw * 255.001953f;
24 }
25
length_impl(T X)26 template <typename T> constexpr T length_impl(T X) { return abs(X); }
27
28 template <typename T, int N>
29 constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
length_vec_impl(vector<T,N> X)30 length_vec_impl(vector<T, N> X) {
31 #if (__has_builtin(__builtin_spirv_length))
32 return __builtin_spirv_length(X);
33 #else
34 return sqrt(dot(X, X));
35 #endif
36 }
37
38 template <typename T>
dst_impl(vector<T,4> Src0,vector<T,4> Src1)39 constexpr vector<T, 4> dst_impl(vector<T, 4> Src0, vector<T, 4> Src1) {
40 return {1, Src0[1] * Src1[1], Src0[2], Src1[3]};
41 }
42
distance_impl(T X,T Y)43 template <typename T> constexpr T distance_impl(T X, T Y) {
44 return length_impl(X - Y);
45 }
46
47 template <typename T, int N>
48 constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
distance_vec_impl(vector<T,N> X,vector<T,N> Y)49 distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
50 return length_vec_impl(X - Y);
51 }
52
dot2add_impl(half2 a,half2 b,float c)53 constexpr float dot2add_impl(half2 a, half2 b, float c) {
54 #if (__has_builtin(__builtin_dx_dot2add))
55 return __builtin_dx_dot2add(a, b, c);
56 #else
57 return dot(a, b) + c;
58 #endif
59 }
60
reflect_impl(T I,T N)61 template <typename T> constexpr T reflect_impl(T I, T N) {
62 return I - 2 * N * I * N;
63 }
64
65 template <typename T, int L>
reflect_vec_impl(vector<T,L> I,vector<T,L> N)66 constexpr vector<T, L> reflect_vec_impl(vector<T, L> I, vector<T, L> N) {
67 #if (__has_builtin(__builtin_spirv_reflect))
68 return __builtin_spirv_reflect(I, N);
69 #else
70 return I - 2 * N * dot(I, N);
71 #endif
72 }
73
fmod_impl(T X,T Y)74 template <typename T> constexpr T fmod_impl(T X, T Y) {
75 #if !defined(__DIRECTX__)
76 return __builtin_elementwise_fmod(X, Y);
77 #else
78 T div = X / Y;
79 bool ge = div >= 0;
80 T frc = frac(abs(div));
81 return select<T>(ge, frc, -frc) * Y;
82 #endif
83 }
84
85 template <typename T, int N>
fmod_vec_impl(vector<T,N> X,vector<T,N> Y)86 constexpr vector<T, N> fmod_vec_impl(vector<T, N> X, vector<T, N> Y) {
87 #if !defined(__DIRECTX__)
88 return __builtin_elementwise_fmod(X, Y);
89 #else
90 vector<T, N> div = X / Y;
91 vector<bool, N> ge = div >= 0;
92 vector<T, N> frc = frac(abs(div));
93 return select<T>(ge, frc, -frc) * Y;
94 #endif
95 }
96
smoothstep_impl(T Min,T Max,T X)97 template <typename T> constexpr T smoothstep_impl(T Min, T Max, T X) {
98 #if (__has_builtin(__builtin_spirv_smoothstep))
99 return __builtin_spirv_smoothstep(Min, Max, X);
100 #else
101 T S = saturate((X - Min) / (Max - Min));
102 return (3 - 2 * S) * S * S;
103 #endif
104 }
105
106 template <typename T, int N>
smoothstep_vec_impl(vector<T,N> Min,vector<T,N> Max,vector<T,N> X)107 constexpr vector<T, N> smoothstep_vec_impl(vector<T, N> Min, vector<T, N> Max,
108 vector<T, N> X) {
109 #if (__has_builtin(__builtin_spirv_smoothstep))
110 return __builtin_spirv_smoothstep(Min, Max, X);
111 #else
112 vector<T, N> S = saturate((X - Min) / (Max - Min));
113 return (3 - 2 * S) * S * S;
114 #endif
115 }
116
lit_impl(T NDotL,T NDotH,T M)117 template <typename T> constexpr vector<T, 4> lit_impl(T NDotL, T NDotH, T M) {
118 bool DiffuseCond = NDotL < 0;
119 T Diffuse = select<T>(DiffuseCond, 0, NDotL);
120 vector<T, 4> Result = {1, Diffuse, 0, 1};
121 // clang-format off
122 bool SpecularCond = or(DiffuseCond, (NDotH < 0));
123 // clang-format on
124 T SpecularExp = exp(log(NDotH) * M);
125 Result[2] = select<T>(SpecularCond, 0, SpecularExp);
126 return Result;
127 }
128
faceforward_impl(T N,T I,T Ng)129 template <typename T> constexpr T faceforward_impl(T N, T I, T Ng) {
130 #if (__has_builtin(__builtin_spirv_faceforward))
131 return __builtin_spirv_faceforward(N, I, Ng);
132 #else
133 return select(dot(I, Ng) < 0, N, -N);
134 #endif
135 }
136
ldexp_impl(T X,T Exp)137 template <typename T> constexpr T ldexp_impl(T X, T Exp) {
138 return exp2(Exp) * X;
139 }
140
141 } // namespace __detail
142 } // namespace hlsl
143
144 #endif // _HLSL_HLSL_INTRINSIC_HELPERS_H_
145