diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2013-06-19 21:54:26 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2013-06-19 21:54:26 +0400 |
commit | f811e6e3ae79be46144d33baf11dbfb618fd4315 (patch) | |
tree | dbcd3941f049fdaac479b5602cb550cc50571e05 | |
parent | 16204bd64759fddc940800f39fc91461ee340424 (diff) |
Cycles: optimized SSE BVH traversal now also works with SSE2 CPUs, so all the
way back to Pentium 4, using a slightly less efficient instruction.
Also ensure /Ox is used for Visual Studio for RelWithDebInfo builds.
-rw-r--r-- | intern/cycles/CMakeLists.txt | 9 | ||||
-rw-r--r-- | intern/cycles/SConscript | 8 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_bvh_traversal.h | 54 | ||||
-rw-r--r-- | intern/cycles/util/util_types.h | 51 |
4 files changed, 85 insertions, 37 deletions
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 06f780eb86f..cc132a2c3b2 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -13,11 +13,14 @@ if(WITH_RAYOPTIMIZATION AND SUPPORT_SSE_BUILD) endif() if(WIN32 AND MSVC) - set(CYCLES_SSE2_KERNEL_FLAGS "/arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /EHsc /GS-") # there is no /arch:SSE3, but intrinsics are available anyway - set(CYCLES_SSE3_KERNEL_FLAGS "/arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /EHsc /GS-") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:fast -D_CRT_SECURE_NO_WARNINGS /EHsc /GS-") + set(CYCLES_SSE2_KERNEL_FLAGS "/arch:SSE2 /fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") + set(CYCLES_SSE3_KERNEL_FLAGS "/arch:SSE2 /fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:fast -D_CRT_SECURE_NO_WARNINGS /Gs-") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Ox") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_RELEASE} /Ox") elseif(CMAKE_COMPILER_IS_GNUCC) set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2 -mfpmath=sse") set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse") diff --git a/intern/cycles/SConscript b/intern/cycles/SConscript index 57f44ae9d52..d1f1b287e00 100644 --- a/intern/cycles/SConscript +++ b/intern/cycles/SConscript @@ -79,12 +79,12 @@ if env['WITH_BF_RAYOPTIMIZATION']: sse3_cxxflags = Split(env['CXXFLAGS']) if env['OURPLATFORM'] == 'win32-vc': - sse2_cxxflags.append('/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /EHsc /Ox /Gs-'.split()) # there is no /arch:SSE3, but intrinsics are available anyway - sse3_cxxflags.append('/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /EHsc /Ox /Gs-'.split()) + sse2_cxxflags.append('/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) + sse3_cxxflags.append('/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) elif env['OURPLATFORM'] == 'win64-vc': - sse2_cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /EHsc /Ox /Gs-'.split()) - sse3_cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /EHsc /Ox /Gs-'.split()) + sse2_cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) + sse3_cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /Gs-'.split()) else: sse2_cxxflags.append('-ffast-math -msse -msse2 -mfpmath=sse'.split()) sse3_cxxflags.append('-ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse'.split()) diff --git a/intern/cycles/kernel/kernel_bvh_traversal.h b/intern/cycles/kernel/kernel_bvh_traversal.h index 900aa7e75fb..8d423b7e7ce 100644 --- a/intern/cycles/kernel/kernel_bvh_traversal.h +++ b/intern/cycles/kernel/kernel_bvh_traversal.h @@ -80,10 +80,10 @@ __device bool BVH_FUNCTION_NAME isect->u = 0.0f; isect->v = 0.0f; -#if defined(__KERNEL_SSSE3__) && !FEATURE(BVH_HAIR_MINIMUM_WIDTH) - const __m128i shuffle_identity = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); - const __m128i shuffle_swap = _mm_set_epi8(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8); - +#if defined(__KERNEL_SSE2__) && !FEATURE(BVH_HAIR_MINIMUM_WIDTH) + const shuffle_swap_t shuf_identity = shuffle_swap_identity(); + const shuffle_swap_t shuf_swap = shuffle_swap_swap(); + const __m128i pn = _mm_set_epi32(0x80000000, 0x80000000, 0x00000000, 0x00000000); __m128 Psplat[3], idirsplat[3]; @@ -97,9 +97,9 @@ __device bool BVH_FUNCTION_NAME __m128 tsplat = _mm_set_ps(-isect->t, -isect->t, 0.0f, 0.0f); - __m128i shufflex = (idir.x >= 0)? shuffle_identity: shuffle_swap; - __m128i shuffley = (idir.y >= 0)? shuffle_identity: shuffle_swap; - __m128i shufflez = (idir.z >= 0)? shuffle_identity: shuffle_swap; + shuffle_swap_t shufflex = (idir.x >= 0)? shuf_identity: shuf_swap; + shuffle_swap_t shuffley = (idir.y >= 0)? shuf_identity: shuf_swap; + shuffle_swap_t shufflez = (idir.z >= 0)? shuf_identity: shuf_swap; #endif /* traversal loop */ @@ -112,7 +112,7 @@ __device bool BVH_FUNCTION_NAME bool traverseChild0, traverseChild1; int nodeAddrChild1; -#if !defined(__KERNEL_SSSE3__) || FEATURE(BVH_HAIR_MINIMUM_WIDTH) +#if !defined(__KERNEL_SSE2__) || FEATURE(BVH_HAIR_MINIMUM_WIDTH) /* Intersect two child bounding boxes, non-SSE version */ float t = isect->t; @@ -166,20 +166,20 @@ __device bool BVH_FUNCTION_NAME traverseChild1 = (c1max >= c1min); #endif -#else // __KERNEL_SSSE3__ - /* Intersect two child bounding boxes, SSSE3 version adapted from Embree */ +#else // __KERNEL_SSE2__ + /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ /* fetch node data */ __m128 *bvh_nodes = (__m128*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; float4 cnodes = ((float4*)bvh_nodes)[3]; /* intersect ray against child nodes */ - const __m128 tminmaxx = _mm_mul_ps(_mm_sub_ps(shuffle8(bvh_nodes[0], shufflex), Psplat[0]), idirsplat[0]); - const __m128 tminmaxy = _mm_mul_ps(_mm_sub_ps(shuffle8(bvh_nodes[1], shuffley), Psplat[1]), idirsplat[1]); - const __m128 tminmaxz = _mm_mul_ps(_mm_sub_ps(shuffle8(bvh_nodes[2], shufflez), Psplat[2]), idirsplat[2]); + const __m128 tminmaxx = _mm_mul_ps(_mm_sub_ps(shuffle_swap(bvh_nodes[0], shufflex), Psplat[0]), idirsplat[0]); + const __m128 tminmaxy = _mm_mul_ps(_mm_sub_ps(shuffle_swap(bvh_nodes[1], shuffley), Psplat[1]), idirsplat[1]); + const __m128 tminmaxz = _mm_mul_ps(_mm_sub_ps(shuffle_swap(bvh_nodes[2], shufflez), Psplat[2]), idirsplat[2]); const __m128 tminmax = _mm_xor_ps(_mm_max_ps(_mm_max_ps(tminmaxx, tminmaxy), _mm_max_ps(tminmaxz, tsplat)), _mm_castsi128_ps(pn)); - const __m128 lrhit = _mm_cmple_ps(tminmax, shuffle8(tminmax, shuffle_swap)); + const __m128 lrhit = _mm_cmple_ps(tminmax, shuffle_swap(tminmax, shuf_swap)); /* decide which nodes to traverse next */ #ifdef __VISIBILITY_FLAG__ @@ -190,14 +190,14 @@ __device bool BVH_FUNCTION_NAME traverseChild0 = (_mm_movemask_ps(lrhit) & 1); traverseChild1 = (_mm_movemask_ps(lrhit) & 2); #endif -#endif // __KERNEL_SSSE3__ +#endif // __KERNEL_SSE2__ nodeAddr = __float_as_int(cnodes.x); nodeAddrChild1 = __float_as_int(cnodes.y); if(traverseChild0 && traverseChild1) { /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSSE3__) || FEATURE(BVH_HAIR_MINIMUM_WIDTH) +#if !defined(__KERNEL_SSE2__) || FEATURE(BVH_HAIR_MINIMUM_WIDTH) bool closestChild1 = (c1min < c0min); #else union { __m128 m128; float v[4]; } uminmax; @@ -244,6 +244,7 @@ __device bool BVH_FUNCTION_NAME /* primitive intersection */ while(primAddr < primAddr2) { bool hit; + #if FEATURE(BVH_SUBSURFACE) /* only primitives from the same object */ uint tri_object = (object == ~0)? kernel_tex_fetch(__prim_object, primAddr): object; @@ -275,14 +276,17 @@ __device bool BVH_FUNCTION_NAME #if FEATURE(BVH_HAIR) if(segment == ~0) #endif + { hit = bvh_triangle_intersect_subsurface(kg, isect, P, idir, object, primAddr, tmax, &num_hits, subsurface_random); + (void)hit; + } } #else hit = bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); /* shadow ray early termination */ -#if defined(__KERNEL_SSSE3__) && !FEATURE(BVH_HAIR_MINIMUM_WIDTH) +#if defined(__KERNEL_SSE2__) && !FEATURE(BVH_HAIR_MINIMUM_WIDTH) if(hit) { if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; @@ -315,7 +319,7 @@ __device bool BVH_FUNCTION_NAME bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax); #endif -#if defined(__KERNEL_SSSE3__) && !FEATURE(BVH_HAIR_MINIMUM_WIDTH) +#if defined(__KERNEL_SSE2__) && !FEATURE(BVH_HAIR_MINIMUM_WIDTH) Psplat[0] = _mm_set_ps1(P.x); Psplat[1] = _mm_set_ps1(P.y); Psplat[2] = _mm_set_ps1(P.z); @@ -326,9 +330,9 @@ __device bool BVH_FUNCTION_NAME tsplat = _mm_set_ps(-isect->t, -isect->t, 0.0f, 0.0f); - shufflex = (idir.x >= 0)? shuffle_identity: shuffle_swap; - shuffley = (idir.y >= 0)? shuffle_identity: shuffle_swap; - shufflez = (idir.z >= 0)? shuffle_identity: shuffle_swap; + shufflex = (idir.x >= 0)? shuf_identity: shuf_swap; + shuffley = (idir.y >= 0)? shuf_identity: shuf_swap; + shufflez = (idir.z >= 0)? shuf_identity: shuf_swap; #endif ++stackPtr; @@ -359,7 +363,7 @@ __device bool BVH_FUNCTION_NAME bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax); #endif -#if defined(__KERNEL_SSSE3__) && !FEATURE(BVH_HAIR_MINIMUM_WIDTH) +#if defined(__KERNEL_SSE2__) && !FEATURE(BVH_HAIR_MINIMUM_WIDTH) Psplat[0] = _mm_set_ps1(P.x); Psplat[1] = _mm_set_ps1(P.y); Psplat[2] = _mm_set_ps1(P.z); @@ -370,9 +374,9 @@ __device bool BVH_FUNCTION_NAME tsplat = _mm_set_ps(-isect->t, -isect->t, 0.0f, 0.0f); - shufflex = (idir.x >= 0)? shuffle_identity: shuffle_swap; - shuffley = (idir.y >= 0)? shuffle_identity: shuffle_swap; - shufflez = (idir.z >= 0)? shuffle_identity: shuffle_swap; + shufflex = (idir.x >= 0)? shuf_identity: shuf_swap; + shuffley = (idir.y >= 0)? shuf_identity: shuf_swap; + shufflez = (idir.z >= 0)? shuf_identity: shuf_swap; #endif object = ~0; diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index d0116186ee8..4fd1e9d8807 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -76,8 +76,8 @@ #define __KERNEL_SSE2__ #endif -#ifndef __KERNEL_SSSE3__ -#define __KERNEL_SSSE3__ +#ifndef __KERNEL_SSE3__ +#define __KERNEL_SSE3__ #endif #ifndef __KERNEL_SSSE3__ @@ -100,7 +100,7 @@ #include <xmmintrin.h> /* SSE 1 */ #include <emmintrin.h> /* SSE 2 */ -#ifdef __KERNEL_SSSE3__ +#ifdef __KERNEL_SSE3__ #include <pmmintrin.h> /* SSE 3 */ #endif #ifdef __KERNEL_SSSE3__ @@ -491,15 +491,56 @@ __device_inline int4 make_int4(const float3& f) #endif -#ifdef __KERNEL_SSSE3__ +#ifdef __KERNEL_SSE2__ /* SSE shuffle utility functions */ -__device_inline const __m128 shuffle8(const __m128& a, const __m128i& shuf) +#ifdef __KERNEL_SSSE3__ + +/* faster version for SSSE3 */ +typedef __m128i shuffle_swap_t; + +__device_inline const shuffle_swap_t shuffle_swap_identity(void) +{ + return _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); +} + +__device_inline const shuffle_swap_t shuffle_swap_swap(void) +{ + return _mm_set_epi8(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8); +} + +__device_inline const __m128 shuffle_swap(const __m128& a, const shuffle_swap_t& shuf) { return _mm_castsi128_ps(_mm_shuffle_epi8(_mm_castps_si128(a), shuf)); } +#else + +/* somewhat slower version for SSE3 */ +typedef int shuffle_swap_t; + +__device_inline const shuffle_swap_t shuffle_swap_identity(void) +{ + return 0; +} + +__device_inline const shuffle_swap_t shuffle_swap_swap(void) +{ + return 1; +} + +__device_inline const __m128 shuffle_swap(const __m128& a, shuffle_swap_t shuf) +{ + /* shuffle value must be a constant, so we need to branch */ + if(shuf) + return _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 3, 2)); + else + return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 1, 0)); +} + +#endif + template<size_t i0, size_t i1, size_t i2, size_t i3> __device_inline const __m128 shuffle(const __m128& a, const __m128& b) { return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0)); |