//===----- hlsl_intrinsic_helpers.h - HLSL helpers intrinsics -------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef _HLSL_HLSL_INTRINSIC_HELPERS_H_ #define _HLSL_HLSL_INTRINSIC_HELPERS_H_ namespace hlsl { namespace __detail { constexpr vector d3d_color_to_ubyte4_impl(vector V) { // Use the same scaling factor used by FXC, and DXC for DXIL // (i.e., 255.001953) // https://github.com/microsoft/DirectXShaderCompiler/blob/070d0d5a2beacef9eeb51037a9b04665716fd6f3/lib/HLSL/HLOperationLower.cpp#L666C1-L697C2 // The DXC implementation refers to a comment on the following stackoverflow // discussion to justify the scaling factor: "Built-in rounding, necessary // because of truncation. 0.001953 * 256 = 0.5" // https://stackoverflow.com/questions/52103720/why-does-d3dcolortoubyte4-multiplies-components-by-255-001953f return V.zyxw * 255.001953f; } template constexpr T length_impl(T X) { return abs(X); } template constexpr enable_if_t::value || is_same::value, T> length_vec_impl(vector X) { #if (__has_builtin(__builtin_spirv_length)) return __builtin_spirv_length(X); #else return sqrt(dot(X, X)); #endif } template constexpr vector dst_impl(vector Src0, vector Src1) { return {1, Src0[1] * Src1[1], Src0[2], Src1[3]}; } template constexpr T distance_impl(T X, T Y) { return length_impl(X - Y); } template constexpr enable_if_t::value || is_same::value, T> distance_vec_impl(vector X, vector Y) { return length_vec_impl(X - Y); } constexpr float dot2add_impl(half2 a, half2 b, float c) { #if (__has_builtin(__builtin_dx_dot2add)) return __builtin_dx_dot2add(a, b, c); #else return dot(a, b) + c; #endif } template constexpr T reflect_impl(T I, T N) { return I - 2 * N * I * N; } template constexpr vector reflect_vec_impl(vector I, vector N) { #if (__has_builtin(__builtin_spirv_reflect)) return __builtin_spirv_reflect(I, N); #else return I - 2 * N * dot(I, N); #endif } template constexpr T fmod_impl(T X, T Y) { #if !defined(__DIRECTX__) return __builtin_elementwise_fmod(X, Y); #else T div = X / Y; bool ge = div >= 0; T frc = frac(abs(div)); return select(ge, frc, -frc) * Y; #endif } template constexpr vector fmod_vec_impl(vector X, vector Y) { #if !defined(__DIRECTX__) return __builtin_elementwise_fmod(X, Y); #else vector div = X / Y; vector ge = div >= 0; vector frc = frac(abs(div)); return select(ge, frc, -frc) * Y; #endif } template constexpr T smoothstep_impl(T Min, T Max, T X) { #if (__has_builtin(__builtin_spirv_smoothstep)) return __builtin_spirv_smoothstep(Min, Max, X); #else T S = saturate((X - Min) / (Max - Min)); return (3 - 2 * S) * S * S; #endif } template constexpr vector smoothstep_vec_impl(vector Min, vector Max, vector X) { #if (__has_builtin(__builtin_spirv_smoothstep)) return __builtin_spirv_smoothstep(Min, Max, X); #else vector S = saturate((X - Min) / (Max - Min)); return (3 - 2 * S) * S * S; #endif } template constexpr vector lit_impl(T NDotL, T NDotH, T M) { bool DiffuseCond = NDotL < 0; T Diffuse = select(DiffuseCond, 0, NDotL); vector Result = {1, Diffuse, 0, 1}; // clang-format off bool SpecularCond = or(DiffuseCond, (NDotH < 0)); // clang-format on T SpecularExp = exp(log(NDotH) * M); Result[2] = select(SpecularCond, 0, SpecularExp); return Result; } template constexpr T faceforward_impl(T N, T I, T Ng) { #if (__has_builtin(__builtin_spirv_faceforward)) return __builtin_spirv_faceforward(N, I, Ng); #else return select(dot(I, Ng) < 0, N, -N); #endif } template constexpr T ldexp_impl(T X, T Exp) { return exp2(Exp) * X; } } // namespace __detail } // namespace hlsl #endif // _HLSL_HLSL_INTRINSIC_HELPERS_H_