// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once #include "node_intersector.h" namespace embree { namespace isa { ////////////////////////////////////////////////////////////////////////////////////// // Ray packet structure used in stream traversal ////////////////////////////////////////////////////////////////////////////////////// template struct TravRayKStream; /* Fast variant */ template struct TravRayKStream { __forceinline TravRayKStream() {} __forceinline TravRayKStream(const Vec3vf& ray_org, const Vec3vf& ray_dir, const vfloat& ray_tnear, const vfloat& ray_tfar) { init(ray_org, ray_dir); tnear = ray_tnear; tfar = ray_tfar; } __forceinline void init(const Vec3vf& ray_org, const Vec3vf& ray_dir) { rdir = rcp_safe(ray_dir); #if defined(__aarch64__) neg_org_rdir = -(ray_org * rdir); #else org_rdir = ray_org * rdir; #endif } Vec3vf rdir; #if defined(__aarch64__) Vec3vf neg_org_rdir; #else Vec3vf org_rdir; #endif vfloat tnear; vfloat tfar; }; template using TravRayKStreamFast = TravRayKStream; /* Robust variant */ template struct TravRayKStream { __forceinline TravRayKStream() {} __forceinline TravRayKStream(const Vec3vf& ray_org, const Vec3vf& ray_dir, const vfloat& ray_tnear, const vfloat& ray_tfar) { init(ray_org, ray_dir); tnear = ray_tnear; tfar = ray_tfar; } __forceinline void init(const Vec3vf& ray_org, const Vec3vf& ray_dir) { rdir = vfloat(1.0f)/(zero_fix(ray_dir)); org = ray_org; } Vec3vf rdir; Vec3vf org; vfloat tnear; vfloat tfar; }; template using TravRayKStreamRobust = TravRayKStream; ////////////////////////////////////////////////////////////////////////////////////// // Fast AABBNode intersection ////////////////////////////////////////////////////////////////////////////////////// template __forceinline size_t intersectNode1(const typename BVHN::AABBNode* __restrict__ node, const TravRayKStreamFast& ray, size_t k, const NearFarPrecalculations& nf) { const vfloat bminX = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.nearX)); const vfloat bminY = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.nearY)); const vfloat bminZ = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.nearZ)); const vfloat bmaxX = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.farX)); const vfloat bmaxY = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.farY)); const vfloat bmaxZ = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.farZ)); #if defined (__aarch64__) const vfloat rminX = madd(bminX, vfloat(ray.rdir.x[k]), vfloat(ray.neg_org_rdir.x[k])); const vfloat rminY = madd(bminY, vfloat(ray.rdir.y[k]), vfloat(ray.neg_org_rdir.y[k])); const vfloat rminZ = madd(bminZ, vfloat(ray.rdir.z[k]), vfloat(ray.neg_org_rdir.z[k])); const vfloat rmaxX = madd(bmaxX, vfloat(ray.rdir.x[k]), vfloat(ray.neg_org_rdir.x[k])); const vfloat rmaxY = madd(bmaxY, vfloat(ray.rdir.y[k]), vfloat(ray.neg_org_rdir.y[k])); const vfloat rmaxZ = madd(bmaxZ, vfloat(ray.rdir.z[k]), vfloat(ray.neg_org_rdir.z[k])); #else const vfloat rminX = msub(bminX, vfloat(ray.rdir.x[k]), vfloat(ray.org_rdir.x[k])); const vfloat rminY = msub(bminY, vfloat(ray.rdir.y[k]), vfloat(ray.org_rdir.y[k])); const vfloat rminZ = msub(bminZ, vfloat(ray.rdir.z[k]), vfloat(ray.org_rdir.z[k])); const vfloat rmaxX = msub(bmaxX, vfloat(ray.rdir.x[k]), vfloat(ray.org_rdir.x[k])); const vfloat rmaxY = msub(bmaxY, vfloat(ray.rdir.y[k]), vfloat(ray.org_rdir.y[k])); const vfloat rmaxZ = msub(bmaxZ, vfloat(ray.rdir.z[k]), vfloat(ray.org_rdir.z[k])); #endif const vfloat rmin = maxi(rminX, rminY, rminZ, vfloat(ray.tnear[k])); const vfloat rmax = mini(rmaxX, rmaxY, rmaxZ, vfloat(ray.tfar[k])); const vbool vmask_first_hit = rmin <= rmax; return movemask(vmask_first_hit) & (((size_t)1 << N)-1); } template __forceinline size_t intersectNodeK(const typename BVHN::AABBNode* __restrict__ node, size_t i, const TravRayKStreamFast& ray, const NearFarPrecalculations& nf) { char* ptr = (char*)&node->lower_x + i*sizeof(float); const vfloat bminX = *(const float*)(ptr + nf.nearX); const vfloat bminY = *(const float*)(ptr + nf.nearY); const vfloat bminZ = *(const float*)(ptr + nf.nearZ); const vfloat bmaxX = *(const float*)(ptr + nf.farX); const vfloat bmaxY = *(const float*)(ptr + nf.farY); const vfloat bmaxZ = *(const float*)(ptr + nf.farZ); #if defined (__aarch64__) const vfloat rminX = madd(bminX, ray.rdir.x, ray.neg_org_rdir.x); const vfloat rminY = madd(bminY, ray.rdir.y, ray.neg_org_rdir.y); const vfloat rminZ = madd(bminZ, ray.rdir.z, ray.neg_org_rdir.z); const vfloat rmaxX = madd(bmaxX, ray.rdir.x, ray.neg_org_rdir.x); const vfloat rmaxY = madd(bmaxY, ray.rdir.y, ray.neg_org_rdir.y); const vfloat rmaxZ = madd(bmaxZ, ray.rdir.z, ray.neg_org_rdir.z); #else const vfloat rminX = msub(bminX, ray.rdir.x, ray.org_rdir.x); const vfloat rminY = msub(bminY, ray.rdir.y, ray.org_rdir.y); const vfloat rminZ = msub(bminZ, ray.rdir.z, ray.org_rdir.z); const vfloat rmaxX = msub(bmaxX, ray.rdir.x, ray.org_rdir.x); const vfloat rmaxY = msub(bmaxY, ray.rdir.y, ray.org_rdir.y); const vfloat rmaxZ = msub(bmaxZ, ray.rdir.z, ray.org_rdir.z); #endif const vfloat rmin = maxi(rminX, rminY, rminZ, ray.tnear); const vfloat rmax = mini(rmaxX, rmaxY, rmaxZ, ray.tfar); const vbool vmask_first_hit = rmin <= rmax; return movemask(vmask_first_hit); } ////////////////////////////////////////////////////////////////////////////////////// // Robust AABBNode intersection ////////////////////////////////////////////////////////////////////////////////////// template __forceinline size_t intersectNode1(const typename BVHN::AABBNode* __restrict__ node, const TravRayKStreamRobust& ray, size_t k, const NearFarPrecalculations& nf) { const vfloat bminX = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.nearX)); const vfloat bminY = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.nearY)); const vfloat bminZ = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.nearZ)); const vfloat bmaxX = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.farX)); const vfloat bmaxY = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.farY)); const vfloat bmaxZ = vfloat(*(const vfloat*)((const char*)&node->lower_x + nf.farZ)); const vfloat rminX = (bminX - vfloat(ray.org.x[k])) * vfloat(ray.rdir.x[k]); const vfloat rminY = (bminY - vfloat(ray.org.y[k])) * vfloat(ray.rdir.y[k]); const vfloat rminZ = (bminZ - vfloat(ray.org.z[k])) * vfloat(ray.rdir.z[k]); const vfloat rmaxX = (bmaxX - vfloat(ray.org.x[k])) * vfloat(ray.rdir.x[k]); const vfloat rmaxY = (bmaxY - vfloat(ray.org.y[k])) * vfloat(ray.rdir.y[k]); const vfloat rmaxZ = (bmaxZ - vfloat(ray.org.z[k])) * vfloat(ray.rdir.z[k]); const float round_up = 1.0f+3.0f*float(ulp); // FIXME: use per instruction rounding for AVX512 const vfloat rmin = max(rminX, rminY, rminZ, vfloat(ray.tnear[k])); const vfloat rmax = round_up *min(rmaxX, rmaxY, rmaxZ, vfloat(ray.tfar[k])); const vbool vmask_first_hit = rmin <= rmax; return movemask(vmask_first_hit) & (((size_t)1 << N)-1); } template __forceinline size_t intersectNodeK(const typename BVHN::AABBNode* __restrict__ node, size_t i, const TravRayKStreamRobust& ray, const NearFarPrecalculations& nf) { char *ptr = (char*)&node->lower_x + i*sizeof(float); const vfloat bminX = *(const float*)(ptr + nf.nearX); const vfloat bminY = *(const float*)(ptr + nf.nearY); const vfloat bminZ = *(const float*)(ptr + nf.nearZ); const vfloat bmaxX = *(const float*)(ptr + nf.farX); const vfloat bmaxY = *(const float*)(ptr + nf.farY); const vfloat bmaxZ = *(const float*)(ptr + nf.farZ); const vfloat rminX = (bminX - ray.org.x) * ray.rdir.x; const vfloat rminY = (bminY - ray.org.y) * ray.rdir.y; const vfloat rminZ = (bminZ - ray.org.z) * ray.rdir.z; const vfloat rmaxX = (bmaxX - ray.org.x) * ray.rdir.x; const vfloat rmaxY = (bmaxY - ray.org.y) * ray.rdir.y; const vfloat rmaxZ = (bmaxZ - ray.org.z) * ray.rdir.z; const float round_up = 1.0f+3.0f*float(ulp); const vfloat rmin = max(rminX, rminY, rminZ, vfloat(ray.tnear)); const vfloat rmax = round_up * min(rmaxX, rmaxY, rmaxZ, vfloat(ray.tfar)); const vbool vmask_first_hit = rmin <= rmax; return movemask(vmask_first_hit); } } }