Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/util/util_math.h
| Show All 20 Lines | |||||
| * | * | ||||
| * Basic math functions on scalar and vector types. This header is used by | * Basic math functions on scalar and vector types. This header is used by | ||||
| * both the kernel code when compiled as C++, and other C++ non-kernel code. */ | * both the kernel code when compiled as C++, and other C++ non-kernel code. */ | ||||
| #ifndef __KERNEL_GPU__ | #ifndef __KERNEL_GPU__ | ||||
| # include <cmath> | # include <cmath> | ||||
| #endif | #endif | ||||
| #ifndef __KERNEL_OPENCL__ | |||||
| # include <float.h> | #include <float.h> | ||||
| # include <math.h> | #include <math.h> | ||||
| # include <stdio.h> | #include <stdio.h> | ||||
| #endif /* __KERNEL_OPENCL__ */ | |||||
| #include "util/util_types.h" | #include "util/util_types.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| /* Float Pi variations */ | /* Float Pi variations */ | ||||
| /* Division */ | /* Division */ | ||||
| Show All 39 Lines | |||||
| #endif | #endif | ||||
| #ifndef M_LN10_F | #ifndef M_LN10_F | ||||
| # define M_LN10_F (2.3025850929940457f) /* ln(10) */ | # define M_LN10_F (2.3025850929940457f) /* ln(10) */ | ||||
| #endif | #endif | ||||
| /* Scalar */ | /* Scalar */ | ||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||
| # ifndef __KERNEL_OPENCL__ | |||||
| ccl_device_inline float fmaxf(float a, float b) | ccl_device_inline float fmaxf(float a, float b) | ||||
| { | { | ||||
| return (a > b) ? a : b; | return (a > b) ? a : b; | ||||
| } | } | ||||
| ccl_device_inline float fminf(float a, float b) | ccl_device_inline float fminf(float a, float b) | ||||
| { | { | ||||
| return (a < b) ? a : b; | return (a < b) ? a : b; | ||||
| } | } | ||||
| # endif /* !__KERNEL_OPENCL__ */ | |||||
| #endif /* _WIN32 */ | #endif /* _WIN32 */ | ||||
| #ifndef __KERNEL_GPU__ | #ifndef __KERNEL_GPU__ | ||||
| using std::isfinite; | using std::isfinite; | ||||
| using std::isnan; | using std::isnan; | ||||
| using std::sqrt; | using std::sqrt; | ||||
| ccl_device_inline int abs(int x) | ccl_device_inline int abs(int x) | ||||
| { | { | ||||
| return (x > 0) ? x : -x; | return (x > 0) ? x : -x; | ||||
| } | } | ||||
| ccl_device_inline int max(int a, int b) | ccl_device_inline int max(int a, int b) | ||||
| { | { | ||||
| return (a > b) ? a : b; | return (a > b) ? a : b; | ||||
| } | } | ||||
| ccl_device_inline int min(int a, int b) | ccl_device_inline int min(int a, int b) | ||||
| { | { | ||||
| return (a < b) ? a : b; | return (a < b) ? a : b; | ||||
| } | } | ||||
| ccl_device_inline uint min(uint a, uint b) | |||||
| { | |||||
| return (a < b) ? a : b; | |||||
| } | |||||
| ccl_device_inline float max(float a, float b) | ccl_device_inline float max(float a, float b) | ||||
| { | { | ||||
| return (a > b) ? a : b; | return (a > b) ? a : b; | ||||
| } | } | ||||
| ccl_device_inline float min(float a, float b) | ccl_device_inline float min(float a, float b) | ||||
| { | { | ||||
| return (a < b) ? a : b; | return (a < b) ? a : b; | ||||
| Show All 31 Lines | ccl_device_inline float min4(float a, float b, float c, float d) | ||||
| return min(min(a, b), min(c, d)); | return min(min(a, b), min(c, d)); | ||||
| } | } | ||||
| ccl_device_inline float max4(float a, float b, float c, float d) | ccl_device_inline float max4(float a, float b, float c, float d) | ||||
| { | { | ||||
| return max(max(a, b), max(c, d)); | return max(max(a, b), max(c, d)); | ||||
| } | } | ||||
| #ifndef __KERNEL_OPENCL__ | |||||
| /* Int/Float conversion */ | /* Int/Float conversion */ | ||||
| ccl_device_inline int as_int(uint i) | ccl_device_inline int as_int(uint i) | ||||
| { | { | ||||
| union { | union { | ||||
| uint ui; | uint ui; | ||||
| int i; | int i; | ||||
| } u; | } u; | ||||
| ▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | union { | ||||
| float f; | float f; | ||||
| } u; | } u; | ||||
| u.i = i; | u.i = i; | ||||
| return u.f; | return u.f; | ||||
| } | } | ||||
| ccl_device_inline int4 __float4_as_int4(float4 f) | ccl_device_inline int4 __float4_as_int4(float4 f) | ||||
| { | { | ||||
| # ifdef __KERNEL_SSE__ | #ifdef __KERNEL_SSE__ | ||||
| return int4(_mm_castps_si128(f.m128)); | return int4(_mm_castps_si128(f.m128)); | ||||
| # else | #else | ||||
| return make_int4( | return make_int4( | ||||
| __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w)); | __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w)); | ||||
| # endif | #endif | ||||
| } | } | ||||
| ccl_device_inline float4 __int4_as_float4(int4 i) | ccl_device_inline float4 __int4_as_float4(int4 i) | ||||
| { | { | ||||
| # ifdef __KERNEL_SSE__ | #ifdef __KERNEL_SSE__ | ||||
| return float4(_mm_castsi128_ps(i.m128)); | return float4(_mm_castsi128_ps(i.m128)); | ||||
| # else | #else | ||||
| return make_float4( | return make_float4( | ||||
| __int_as_float(i.x), __int_as_float(i.y), __int_as_float(i.z), __int_as_float(i.w)); | __int_as_float(i.x), __int_as_float(i.y), __int_as_float(i.z), __int_as_float(i.w)); | ||||
| # endif | #endif | ||||
| } | } | ||||
| #endif /* __KERNEL_OPENCL__ */ | |||||
| /* Versions of functions which are safe for fast math. */ | /* Versions of functions which are safe for fast math. */ | ||||
| ccl_device_inline bool isnan_safe(float f) | ccl_device_inline bool isnan_safe(float f) | ||||
| { | { | ||||
| unsigned int x = __float_as_uint(f); | unsigned int x = __float_as_uint(f); | ||||
| return (x << 1) > 0xff000000u; | return (x << 1) > 0xff000000u; | ||||
| } | } | ||||
| ccl_device_inline bool isfinite_safe(float f) | ccl_device_inline bool isfinite_safe(float f) | ||||
| { | { | ||||
| /* By IEEE 754 rule, 2*Inf equals Inf */ | /* By IEEE 754 rule, 2*Inf equals Inf */ | ||||
| unsigned int x = __float_as_uint(f); | unsigned int x = __float_as_uint(f); | ||||
| return (f == f) && (x == 0 || x == (1u << 31) || (f != 2.0f * f)) && !((x << 1) > 0xff000000u); | return (f == f) && (x == 0 || x == (1u << 31) || (f != 2.0f * f)) && !((x << 1) > 0xff000000u); | ||||
| } | } | ||||
| ccl_device_inline float ensure_finite(float v) | ccl_device_inline float ensure_finite(float v) | ||||
| { | { | ||||
| return isfinite_safe(v) ? v : 0.0f; | return isfinite_safe(v) ? v : 0.0f; | ||||
| } | } | ||||
| #ifndef __KERNEL_OPENCL__ | |||||
| ccl_device_inline int clamp(int a, int mn, int mx) | ccl_device_inline int clamp(int a, int mn, int mx) | ||||
| { | { | ||||
| return min(max(a, mn), mx); | return min(max(a, mn), mx); | ||||
| } | } | ||||
| ccl_device_inline float clamp(float a, float mn, float mx) | ccl_device_inline float clamp(float a, float mn, float mx) | ||||
| { | { | ||||
| return min(max(a, mn), mx); | return min(max(a, mn), mx); | ||||
| Show All 13 Lines | else if (x >= edge1) | ||||
| result = 1.0f; | result = 1.0f; | ||||
| else { | else { | ||||
| float t = (x - edge0) / (edge1 - edge0); | float t = (x - edge0) / (edge1 - edge0); | ||||
| result = (3.0f - 2.0f * t) * (t * t); | result = (3.0f - 2.0f * t) * (t * t); | ||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||
| #endif /* __KERNEL_OPENCL__ */ | |||||
| #ifndef __KERNEL_CUDA__ | #ifndef __KERNEL_CUDA__ | ||||
| ccl_device_inline float saturate(float a) | ccl_device_inline float saturate(float a) | ||||
| { | { | ||||
| return clamp(a, 0.0f, 1.0f); | return clamp(a, 0.0f, 1.0f); | ||||
| } | } | ||||
| #endif /* __KERNEL_CUDA__ */ | #endif /* __KERNEL_CUDA__ */ | ||||
| ccl_device_inline int float_to_int(float f) | ccl_device_inline int float_to_int(float f) | ||||
| ▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | |||||
| #include "util/util_math_float2.h" | #include "util/util_math_float2.h" | ||||
| #include "util/util_math_float3.h" | #include "util/util_math_float3.h" | ||||
| #include "util/util_math_float4.h" | #include "util/util_math_float4.h" | ||||
| #include "util/util_rect.h" | #include "util/util_rect.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| #ifndef __KERNEL_OPENCL__ | |||||
| /* Interpolation */ | /* Interpolation */ | ||||
| template<class A, class B> A lerp(const A &a, const A &b, const B &t) | template<class A, class B> A lerp(const A &a, const A &b, const B &t) | ||||
| { | { | ||||
| return (A)(a * ((B)1 - t) + b * t); | return (A)(a * ((B)1 - t) + b * t); | ||||
| } | } | ||||
| #endif /* __KERNEL_OPENCL__ */ | |||||
| /* Triangle */ | /* Triangle */ | ||||
| #ifndef __KERNEL_OPENCL__ | |||||
| ccl_device_inline float triangle_area(const float3 &v1, const float3 &v2, const float3 &v3) | ccl_device_inline float triangle_area(const float3 &v1, const float3 &v2, const float3 &v3) | ||||
| #else | |||||
| ccl_device_inline float triangle_area(const float3 v1, const float3 v2, const float3 v3) | |||||
| #endif | |||||
| { | { | ||||
| return len(cross(v3 - v2, v1 - v2)) * 0.5f; | return len(cross(v3 - v2, v1 - v2)) * 0.5f; | ||||
| } | } | ||||
| /* Orthonormal vectors */ | /* Orthonormal vectors */ | ||||
| ccl_device_inline void make_orthonormals(const float3 N, float3 *a, float3 *b) | ccl_device_inline void make_orthonormals(const float3 N, float3 *a, float3 *b) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | |||||
| ccl_device_inline float pow22(float a) | ccl_device_inline float pow22(float a) | ||||
| { | { | ||||
| return sqr(a * sqr(sqr(sqr(a)) * a)); | return sqr(a * sqr(sqr(sqr(a)) * a)); | ||||
| } | } | ||||
| ccl_device_inline float beta(float x, float y) | ccl_device_inline float beta(float x, float y) | ||||
| { | { | ||||
| #ifndef __KERNEL_OPENCL__ | |||||
| return expf(lgammaf(x) + lgammaf(y) - lgammaf(x + y)); | return expf(lgammaf(x) + lgammaf(y) - lgammaf(x + y)); | ||||
| #else | |||||
| return expf(lgamma(x) + lgamma(y) - lgamma(x + y)); | |||||
| #endif | |||||
| } | } | ||||
| ccl_device_inline float xor_signmask(float x, int y) | ccl_device_inline float xor_signmask(float x, int y) | ||||
| { | { | ||||
| return __int_as_float(__float_as_int(x) ^ y); | return __int_as_float(__float_as_int(x) ^ y); | ||||
| } | } | ||||
| ccl_device float bits_to_01(uint bits) | ccl_device float bits_to_01(uint bits) | ||||
| { | { | ||||
| return bits * (1.0f / (float)0xFFFFFFFF); | return bits * (1.0f / (float)0xFFFFFFFF); | ||||
| } | } | ||||
| ccl_device_inline uint count_leading_zeros(uint x) | ccl_device_inline uint count_leading_zeros(uint x) | ||||
| { | { | ||||
| #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) | #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) | ||||
| return __clz(x); | return __clz(x); | ||||
| #elif defined(__KERNEL_OPENCL__) | |||||
| return clz(x); | |||||
| #else | #else | ||||
| assert(x != 0); | assert(x != 0); | ||||
| # ifdef _MSC_VER | # ifdef _MSC_VER | ||||
| unsigned long leading_zero = 0; | unsigned long leading_zero = 0; | ||||
| _BitScanReverse(&leading_zero, x); | _BitScanReverse(&leading_zero, x); | ||||
| return (31 - leading_zero); | return (31 - leading_zero); | ||||
| # else | # else | ||||
| return __builtin_clz(x); | return __builtin_clz(x); | ||||
| # endif | # endif | ||||
| #endif | #endif | ||||
| } | } | ||||
| ccl_device_inline uint count_trailing_zeros(uint x) | ccl_device_inline uint count_trailing_zeros(uint x) | ||||
| { | { | ||||
| #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) | #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) | ||||
| return (__ffs(x) - 1); | return (__ffs(x) - 1); | ||||
| #elif defined(__KERNEL_OPENCL__) | |||||
| return (31 - count_leading_zeros(x & -x)); | |||||
| #else | #else | ||||
| assert(x != 0); | assert(x != 0); | ||||
| # ifdef _MSC_VER | # ifdef _MSC_VER | ||||
| unsigned long ctz = 0; | unsigned long ctz = 0; | ||||
| _BitScanForward(&ctz, x); | _BitScanForward(&ctz, x); | ||||
| return ctz; | return ctz; | ||||
| # else | # else | ||||
| return __builtin_ctz(x); | return __builtin_ctz(x); | ||||
| # endif | # endif | ||||
| #endif | #endif | ||||
| } | } | ||||
| ccl_device_inline uint find_first_set(uint x) | ccl_device_inline uint find_first_set(uint x) | ||||
| { | { | ||||
| #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) | #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) | ||||
| return __ffs(x); | return __ffs(x); | ||||
| #elif defined(__KERNEL_OPENCL__) | |||||
| return (x != 0) ? (32 - count_leading_zeros(x & (-x))) : 0; | |||||
| #else | #else | ||||
| # ifdef _MSC_VER | # ifdef _MSC_VER | ||||
| return (x != 0) ? (32 - count_leading_zeros(x & (-x))) : 0; | return (x != 0) ? (32 - count_leading_zeros(x & (-x))) : 0; | ||||
| # else | # else | ||||
| return __builtin_ffs(x); | return __builtin_ffs(x); | ||||
| # endif | # endif | ||||
| #endif | #endif | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
| * which are avoided by this method. | * which are avoided by this method. | ||||
| * Based on "Mangled Angles" from https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf | * Based on "Mangled Angles" from https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf | ||||
| */ | */ | ||||
| ccl_device_inline float precise_angle(float3 a, float3 b) | ccl_device_inline float precise_angle(float3 a, float3 b) | ||||
| { | { | ||||
| return 2.0f * atan2f(len(a - b), len(a + b)); | return 2.0f * atan2f(len(a - b), len(a + b)); | ||||
| } | } | ||||
| /* Return value which is greater than the given one and is a power of two. */ | |||||
| ccl_device_inline uint next_power_of_two(uint x) | |||||
| { | |||||
| return x == 0 ? 1 : 1 << (32 - count_leading_zeros(x)); | |||||
| } | |||||
| /* Return value which is lower than the given one and is a power of two. */ | |||||
| ccl_device_inline uint prev_power_of_two(uint x) | |||||
| { | |||||
| return x < 2 ? x : 1 << (31 - count_leading_zeros(x - 1)); | |||||
| } | |||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||
| #endif /* __UTIL_MATH_H__ */ | #endif /* __UTIL_MATH_H__ */ | ||||