// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once #include "../common/ray.h" #include "../common/context.h" #include "filter.h" namespace embree { namespace isa { template struct UVIdentity { __forceinline void operator() (vfloat& u, vfloat& v, Vec3vf& Ng) const {} }; template struct Intersect1Epilog1 { RayHit& ray; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1Epilog1(RayHit& ray, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template __forceinline bool operator() (Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask) == 0) return false; #endif hit.finalize(); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng); const float old_t = ray.tfar; ray.tfar = hit.t; bool found = runIntersectionFilter1(geometry,ray,context,h); if (!found) ray.tfar = old_t; return found; } } #endif /* update hit information */ ray.tfar = hit.t; ray.Ng = hit.Ng; ray.u = hit.u; ray.v = hit.v; ray.primID = primID; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); return true; } }; template struct Occluded1Epilog1 { Ray& ray; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1Epilog1(Ray& ray, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template __forceinline bool operator() (Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask) == 0) return false; #endif hit.finalize(); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng); const float old_t = ray.tfar; ray.tfar = hit.t; const bool found = runOcclusionFilter1(geometry,ray,context,h); if (!found) ray.tfar = old_t; return found; } } #endif return true; } }; template struct Intersect1KEpilog1 { RayHitK& ray; size_t k; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1KEpilog1(RayHitK& ray, size_t k, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} template __forceinline bool operator() (Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask[k]) == 0) return false; #endif hit.finalize(); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { HitK h(context->user,geomID,primID,hit.u,hit.v,hit.Ng); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t; const bool found = any(runIntersectionFilter(vbool(1<(context->user->instID, ray.instID, k); return true; } }; template struct Occluded1KEpilog1 { RayK& ray; size_t k; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1KEpilog1(RayK& ray, size_t k, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} template __forceinline bool operator() (Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask[k]) == 0) return false; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { hit.finalize(); HitK h(context->user,geomID,primID,hit.u,hit.v,hit.Ng); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t; const bool found = any(runOcclusionFilter(vbool(1< struct Intersect1EpilogM { RayHit& ray; IntersectContext* context; const vuint& geomIDs; const vuint& primIDs; __forceinline Intersect1EpilogM(RayHit& ray, IntersectContext* context, const vuint& geomIDs, const vuint& primIDs) : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {} template __forceinline bool operator() (const vbool& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; vbool valid = valid_i; hit.finalize(); size_t i = select_min(valid,hit.vt); unsigned int geomID = geomIDs[i]; /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK) bool foundhit = false; goto entry; while (true) { if (unlikely(none(valid))) return foundhit; i = select_min(valid,hit.vt); geomID = geomIDs[i]; entry: Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* goto next hit if mask test fails */ if ((geometry->mask & ray.mask) == 0) { clear(valid,i); continue; } #endif #if defined(EMBREE_FILTER_FUNCTION) /* call intersection filter function */ if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { const Vec2f uv = hit.uv(i); HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i)); const float old_t = ray.tfar; ray.tfar = hit.t(i); const bool found = runIntersectionFilter1(geometry,ray,context,h); if (!found) ray.tfar = old_t; foundhit |= found; clear(valid,i); valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value continue; } } #endif break; } #endif /* update hit information */ const Vec2f uv = hit.uv(i); ray.tfar = hit.vt[i]; ray.Ng.x = hit.vNg.x[i]; ray.Ng.y = hit.vNg.y[i]; ray.Ng.z = hit.vNg.z[i]; ray.u = uv.x; ray.v = uv.y; ray.primID = primIDs[i]; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); return true; } }; template struct Occluded1EpilogM { Ray& ray; IntersectContext* context; const vuint& geomIDs; const vuint& primIDs; __forceinline Occluded1EpilogM(Ray& ray, IntersectContext* context, const vuint& geomIDs, const vuint& primIDs) : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {} template __forceinline bool operator() (const vbool& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK) if (unlikely(filter)) hit.finalize(); /* called only once */ vbool valid = valid_i; size_t m=movemask(valid); goto entry; while (true) { if (unlikely(m == 0)) return false; entry: size_t i=bsf(m); const unsigned int geomID = geomIDs[i]; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* goto next hit if mask test fails */ if ((geometry->mask & ray.mask) == 0) { m=btc(m,i); continue; } #endif #if defined(EMBREE_FILTER_FUNCTION) /* if we have no filter then the test passed */ if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { const Vec2f uv = hit.uv(i); HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i)); const float old_t = ray.tfar; ray.tfar = hit.t(i); if (runOcclusionFilter1(geometry,ray,context,h)) return true; ray.tfar = old_t; m=btc(m,i); continue; } } #endif break; } #endif return true; } }; template struct Intersect1EpilogMU { RayHit& ray; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1EpilogMU(RayHit& ray, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template __forceinline bool operator() (const vbool& valid_i, Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask) == 0) return false; #endif vbool valid = valid_i; hit.finalize(); size_t i = select_min(valid,hit.vt); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { bool foundhit = false; while (true) { /* call intersection filter function */ Vec2f uv = hit.uv(i); const float old_t = ray.tfar; ray.tfar = hit.t(i); HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i)); const bool found = runIntersectionFilter1(geometry,ray,context,h); if (!found) ray.tfar = old_t; foundhit |= found; clear(valid,i); valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value if (unlikely(none(valid))) break; i = select_min(valid,hit.vt); } return foundhit; } #endif /* update hit information */ const Vec2f uv = hit.uv(i); const Vec3fa Ng = hit.Ng(i); ray.tfar = hit.t(i); ray.Ng.x = Ng.x; ray.Ng.y = Ng.y; ray.Ng.z = Ng.z; ray.u = uv.x; ray.v = uv.y; ray.primID = primID; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); return true; } }; template struct Occluded1EpilogMU { Ray& ray; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1EpilogMU(Ray& ray, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template __forceinline bool operator() (const vbool& valid, Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask) == 0) return false; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { hit.finalize(); for (size_t m=movemask(valid), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) { const Vec2f uv = hit.uv(i); const float old_t = ray.tfar; ray.tfar = hit.t(i); HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i)); if (runOcclusionFilter1(geometry,ray,context,h)) return true; ray.tfar = old_t; } return false; } #endif return true; } }; template struct IntersectKEpilogM { RayHitK& ray; IntersectContext* context; const vuint& geomIDs; const vuint& primIDs; const size_t i; __forceinline IntersectKEpilogM(RayHitK& ray, IntersectContext* context, const vuint& geomIDs, const vuint& primIDs, size_t i) : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {} template __forceinline vbool operator() (const vbool& valid_i, const Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; vfloat u, v, t; Vec3vf Ng; vbool valid = valid_i; std::tie(u,v,t,Ng) = hit(); const unsigned int geomID = geomIDs[i]; const unsigned int primID = primIDs[i]; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); /* ray masking test */ #if defined(EMBREE_RAY_MASK) valid &= (geometry->mask & ray.mask) != 0; if (unlikely(none(valid))) return false; #endif /* occlusion filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { HitK h(context->user,geomID,primID,u,v,Ng); const vfloat old_t = ray.tfar; ray.tfar = select(valid,t,ray.tfar); const vbool m_accept = runIntersectionFilter(valid,geometry,ray,context,h); ray.tfar = select(m_accept,ray.tfar,old_t); return m_accept; } } #endif /* update hit information */ vfloat::store(valid,&ray.tfar,t); vfloat::store(valid,&ray.Ng.x,Ng.x); vfloat::store(valid,&ray.Ng.y,Ng.y); vfloat::store(valid,&ray.Ng.z,Ng.z); vfloat::store(valid,&ray.u,u); vfloat::store(valid,&ray.v,v); vuint::store(valid,&ray.primID,primID); vuint::store(valid,&ray.geomID,geomID); instance_id_stack::copy_UV(context->user->instID, ray.instID, valid); return valid; } }; template struct OccludedKEpilogM { vbool& valid0; RayK& ray; IntersectContext* context; const vuint& geomIDs; const vuint& primIDs; const size_t i; __forceinline OccludedKEpilogM(vbool& valid0, RayK& ray, IntersectContext* context, const vuint& geomIDs, const vuint& primIDs, size_t i) : valid0(valid0), ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {} template __forceinline vbool operator() (const vbool& valid_i, const Hit& hit) const { vbool valid = valid_i; /* ray masking test */ Scene* scene MAYBE_UNUSED = context->scene; const unsigned int geomID MAYBE_UNUSED = geomIDs[i]; const unsigned int primID MAYBE_UNUSED = primIDs[i]; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) valid &= (geometry->mask & ray.mask) != 0; if (unlikely(none(valid))) return valid; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { vfloat u, v, t; Vec3vf Ng; std::tie(u,v,t,Ng) = hit(); HitK h(context->user,geomID,primID,u,v,Ng); const vfloat old_t = ray.tfar; ray.tfar = select(valid,t,ray.tfar); valid = runOcclusionFilter(valid,geometry,ray,context,h); ray.tfar = select(valid,ray.tfar,old_t); } } #endif /* update occlusion */ valid0 = valid0 & !valid; return valid; } }; template struct IntersectKEpilogMU { RayHitK& ray; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline IntersectKEpilogMU(RayHitK& ray, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template __forceinline vbool operator() (const vbool& valid_org, const Hit& hit) const { vbool valid = valid_org; vfloat u, v, t; Vec3vf Ng; std::tie(u,v,t,Ng) = hit(); Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); /* ray masking test */ #if defined(EMBREE_RAY_MASK) valid &= (geometry->mask & ray.mask) != 0; if (unlikely(none(valid))) return false; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { HitK h(context->user,geomID,primID,u,v,Ng); const vfloat old_t = ray.tfar; ray.tfar = select(valid,t,ray.tfar); const vbool m_accept = runIntersectionFilter(valid,geometry,ray,context,h); ray.tfar = select(m_accept,ray.tfar,old_t); return m_accept; } } #endif /* update hit information */ vfloat::store(valid,&ray.tfar,t); vfloat::store(valid,&ray.Ng.x,Ng.x); vfloat::store(valid,&ray.Ng.y,Ng.y); vfloat::store(valid,&ray.Ng.z,Ng.z); vfloat::store(valid,&ray.u,u); vfloat::store(valid,&ray.v,v); vuint::store(valid,&ray.primID,primID); vuint::store(valid,&ray.geomID,geomID); instance_id_stack::copy_UV(context->user->instID, ray.instID, valid); return valid; } }; template struct OccludedKEpilogMU { vbool& valid0; RayK& ray; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline OccludedKEpilogMU(vbool& valid0, RayK& ray, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : valid0(valid0), ray(ray), context(context), geomID(geomID), primID(primID) {} template __forceinline vbool operator() (const vbool& valid_i, const Hit& hit) const { vbool valid = valid_i; Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) valid &= (geometry->mask & ray.mask) != 0; if (unlikely(none(valid))) return false; #endif /* occlusion filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { vfloat u, v, t; Vec3vf Ng; std::tie(u,v,t,Ng) = hit(); HitK h(context->user,geomID,primID,u,v,Ng); const vfloat old_t = ray.tfar; ray.tfar = select(valid,t,ray.tfar); valid = runOcclusionFilter(valid,geometry,ray,context,h); ray.tfar = select(valid,ray.tfar,old_t); } } #endif /* update occlusion */ valid0 = valid0 & !valid; return valid; } }; template struct Intersect1KEpilogM { RayHitK& ray; size_t k; IntersectContext* context; const vuint& geomIDs; const vuint& primIDs; __forceinline Intersect1KEpilogM(RayHitK& ray, size_t k, IntersectContext* context, const vuint& geomIDs, const vuint& primIDs) : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {} template __forceinline bool operator() (const vbool& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; vbool valid = valid_i; hit.finalize(); size_t i = select_min(valid,hit.vt); assert(iget(geomID); #if defined(EMBREE_RAY_MASK) /* goto next hit if mask test fails */ if ((geometry->mask & ray.mask[k]) == 0) { clear(valid,i); continue; } #endif #if defined(EMBREE_FILTER_FUNCTION) /* call intersection filter function */ if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { assert(i h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i)); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t(i); const bool found = any(runIntersectionFilter(vbool(1<(context->user->instID, ray.instID, k); return true; } }; template struct Occluded1KEpilogM { RayK& ray; size_t k; IntersectContext* context; const vuint& geomIDs; const vuint& primIDs; __forceinline Occluded1KEpilogM(RayK& ray, size_t k, IntersectContext* context, const vuint& geomIDs, const vuint& primIDs) : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {} template __forceinline bool operator() (const vbool& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK) if (unlikely(filter)) hit.finalize(); /* called only once */ vbool valid = valid_i; size_t m=movemask(valid); goto entry; while (true) { if (unlikely(m == 0)) return false; entry: size_t i=bsf(m); const unsigned int geomID = geomIDs[i]; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* goto next hit if mask test fails */ if ((geometry->mask & ray.mask[k]) == 0) { m=btc(m,i); continue; } #endif #if defined(EMBREE_FILTER_FUNCTION) /* execute occlusion filer */ if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { const Vec2f uv = hit.uv(i); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t(i); HitK h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i)); if (any(runOcclusionFilter(vbool(1< struct Intersect1KEpilogMU { RayHitK& ray; size_t k; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1KEpilogMU(RayHitK& ray, size_t k, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} template __forceinline bool operator() (const vbool& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* ray mask test */ if ((geometry->mask & ray.mask[k]) == 0) return false; #endif /* finalize hit calculation */ vbool valid = valid_i; hit.finalize(); size_t i = select_min(valid,hit.vt); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { bool foundhit = false; while (true) { const Vec2f uv = hit.uv(i); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t(i); HitK h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i)); const bool found = any(runIntersectionFilter(vbool(1<(context->user->instID, ray.instID, k); return true; } }; template struct Occluded1KEpilogMU { RayK& ray; size_t k; IntersectContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1KEpilogMU(RayK& ray, size_t k, IntersectContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} template __forceinline bool operator() (const vbool& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* ray mask test */ if ((geometry->mask & ray.mask[k]) == 0) return false; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { hit.finalize(); for (size_t m=movemask(valid_i), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) { const Vec2f uv = hit.uv(i); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t(i); HitK h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i)); if (any(runOcclusionFilter(vbool(1<