175 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _HLSL_HLSL_INTRINSIC_HELPERS_H_10#define _HLSL_HLSL_INTRINSIC_HELPERS_H_11 12namespace hlsl {13namespace __detail {14 15constexpr int4 d3d_color_to_ubyte4_impl(float4 V) {16 // Use the same scaling factor used by FXC, and DXC for DXIL17 // (i.e., 255.001953)18 // https://github.com/microsoft/DirectXShaderCompiler/blob/070d0d5a2beacef9eeb51037a9b04665716fd6f3/lib/HLSL/HLOperationLower.cpp#L666C1-L697C219 // The DXC implementation refers to a comment on the following stackoverflow20 // discussion to justify the scaling factor: "Built-in rounding, necessary21 // because of truncation. 0.001953 * 256 = 0.5"22 // https://stackoverflow.com/questions/52103720/why-does-d3dcolortoubyte4-multiplies-components-by-255-001953f23 return V.zyxw * 255.001953f;24}25 26template <typename T> constexpr T length_impl(T X) { return abs(X); }27 28template <typename T, int N>29constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>30length_vec_impl(vector<T, N> X) {31#if (__has_builtin(__builtin_spirv_length))32 return __builtin_spirv_length(X);33#else34 return sqrt(dot(X, X));35#endif36}37 38template <typename T>39constexpr 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 43template <typename T> constexpr T distance_impl(T X, T Y) {44 return length_impl(X - Y);45}46 47template <typename T, int N>48constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>49distance_vec_impl(vector<T, N> X, vector<T, N> Y) {50 return length_vec_impl(X - Y);51}52 53constexpr 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#else57 return dot(a, b) + c;58#endif59}60 61template <typename T> constexpr T reflect_impl(T I, T N) {62 return I - 2 * N * I * N;63}64 65template <typename T, int L>66constexpr 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#else70 return I - 2 * N * dot(I, N);71#endif72}73 74template <typename T, typename U> constexpr T refract_impl(T I, T N, U Eta) {75#if (__has_builtin(__builtin_spirv_refract))76 return __builtin_spirv_refract(I, N, Eta);77#endif78 T Mul = dot(N, I);79 T K = 1 - Eta * Eta * (1 - Mul * Mul);80 T Result = (Eta * I - (Eta * Mul + sqrt(K)) * N);81 return select<T>(K < 0, static_cast<T>(0), Result);82}83 84template <typename T> constexpr T fmod_impl(T X, T Y) {85#if !defined(__DIRECTX__)86 return __builtin_elementwise_fmod(X, Y);87#else88 T div = X / Y;89 bool ge = div >= 0;90 T frc = frac(abs(div));91 return select<T>(ge, frc, -frc) * Y;92#endif93}94 95template <typename T, int N>96constexpr vector<T, N> fmod_vec_impl(vector<T, N> X, vector<T, N> Y) {97#if !defined(__DIRECTX__)98 return __builtin_elementwise_fmod(X, Y);99#else100 vector<T, N> div = X / Y;101 vector<bool, N> ge = div >= 0;102 vector<T, N> frc = frac(abs(div));103 return select<T>(ge, frc, -frc) * Y;104#endif105}106 107template <typename T> constexpr T smoothstep_impl(T Min, T Max, T X) {108#if (__has_builtin(__builtin_spirv_smoothstep))109 return __builtin_spirv_smoothstep(Min, Max, X);110#else111 T S = saturate((X - Min) / (Max - Min));112 return (3 - 2 * S) * S * S;113#endif114}115 116template <typename T, int N>117constexpr vector<T, N> smoothstep_vec_impl(vector<T, N> Min, vector<T, N> Max,118 vector<T, N> X) {119#if (__has_builtin(__builtin_spirv_smoothstep))120 return __builtin_spirv_smoothstep(Min, Max, X);121#else122 vector<T, N> S = saturate((X - Min) / (Max - Min));123 return (3 - 2 * S) * S * S;124#endif125}126 127template <typename T> constexpr vector<T, 4> lit_impl(T NDotL, T NDotH, T M) {128 bool DiffuseCond = NDotL < 0;129 T Diffuse = select<T>(DiffuseCond, 0, NDotL);130 vector<T, 4> Result = {1, Diffuse, 0, 1};131 // clang-format off132 bool SpecularCond = or(DiffuseCond, (NDotH < 0));133 // clang-format on134 T SpecularExp = exp(log(NDotH) * M);135 Result[2] = select<T>(SpecularCond, 0, SpecularExp);136 return Result;137}138 139template <typename T> constexpr T faceforward_impl(T N, T I, T Ng) {140 return select(dot(I, Ng) < 0, N, -N);141}142 143template <typename T> constexpr T ldexp_impl(T X, T Exp) {144 return exp2(Exp) * X;145}146 147template <typename K, typename T, int BitWidth>148constexpr K firstbithigh_impl(T X) {149 K FBH = __builtin_hlsl_elementwise_firstbithigh(X);150#if defined(__DIRECTX__)151 // The firstbithigh DXIL ops count bits from the wrong side, so we need to152 // invert it for DirectX.153 K Inversion = (BitWidth - 1) - FBH;154 FBH = select(FBH == -1, FBH, Inversion);155#endif156 return FBH;157}158 159template <typename T> constexpr T fwidth_impl(T input) {160#if (__has_builtin(__builtin_spirv_fwidth))161 return __builtin_spirv_fwidth(input);162#else163 T derivCoarseX = ddx_coarse(input);164 derivCoarseX = abs(derivCoarseX);165 T derivCoarseY = ddy_coarse(input);166 derivCoarseY = abs(derivCoarseY);167 return derivCoarseX + derivCoarseY;168#endif169}170 171} // namespace __detail172} // namespace hlsl173 174#endif // _HLSL_HLSL_INTRINSIC_HELPERS_H_175