Revision control
++ // 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<int M>
++ struct UVIdentity {
++ __forceinline void operator() (vfloat<M>& u, vfloat<M>& v, Vec3vf<M>& Ng) const {}
++ };
++
++
++ template<bool filter>
++ 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<typename Hit>
++ __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<bool filter>
++ 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<typename Hit>
++ __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<int K, bool filter>
++ struct Intersect1KEpilog1
++ {
++ RayHitK<K>& ray;
++ size_t k;
++ IntersectContext* context;
++ const unsigned int geomID;
++ const unsigned int primID;
++
++ __forceinline Intersect1KEpilog1(RayHitK<K>& 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<typename Hit>
++ __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<K> 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<K>(1<<k),geometry,ray,context,h));
++ if (!found) ray.tfar[k] = old_t;
++ return found;
++ }
++ }
++ #endif
++
++ /* update hit information */
++ ray.tfar[k] = hit.t;
++ ray.Ng.x[k] = hit.Ng.x;
++ ray.Ng.y[k] = hit.Ng.y;
++ ray.Ng.z[k] = hit.Ng.z;
++ ray.u[k] = hit.u;
++ ray.v[k] = hit.v;
++ ray.primID[k] = primID;
++ ray.geomID[k] = geomID;
++ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
++ return true;
++ }
++ };
++
++ template<int K, bool filter>
++ struct Occluded1KEpilog1
++ {
++ RayK<K>& ray;
++ size_t k;
++ IntersectContext* context;
++ const unsigned int geomID;
++ const unsigned int primID;
++
++ __forceinline Occluded1KEpilog1(RayK<K>& 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<typename Hit>
++ __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<K> 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<K>(1<<k),geometry,ray,context,h));
++ if (!found) ray.tfar[k] = old_t;
++ return found;
++ }
++ }
++ #endif
++ return true;
++ }
++ };
++
++ template<int M, bool filter>
++ struct Intersect1EpilogM
++ {
++ RayHit& ray;
++ IntersectContext* context;
++ const vuint<M>& geomIDs;
++ const vuint<M>& primIDs;
++
++ __forceinline Intersect1EpilogM(RayHit& ray,
++ IntersectContext* context,
++ const vuint<M>& geomIDs,
++ const vuint<M>& primIDs)
++ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
++
++ template<typename Hit>
++ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
++ {
++ Scene* scene MAYBE_UNUSED = context->scene;
++ vbool<M> 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<int M, bool filter>
++ struct Occluded1EpilogM
++ {
++ Ray& ray;
++ IntersectContext* context;
++ const vuint<M>& geomIDs;
++ const vuint<M>& primIDs;
++
++ __forceinline Occluded1EpilogM(Ray& ray,
++ IntersectContext* context,
++ const vuint<M>& geomIDs,
++ const vuint<M>& primIDs)
++ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
++
++ template<typename Hit>
++ __forceinline bool operator() (const vbool<M>& 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<M> 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<int M, bool filter>
++ 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<typename Hit>
++ __forceinline bool operator() (const vbool<M>& 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<M> 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<int M, bool filter>
++ 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<typename Hit>
++ __forceinline bool operator() (const vbool<M>& 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<int M, int K, bool filter>
++ struct IntersectKEpilogM
++ {
++ RayHitK<K>& ray;
++ IntersectContext* context;
++ const vuint<M>& geomIDs;
++ const vuint<M>& primIDs;
++ const size_t i;
++
++ __forceinline IntersectKEpilogM(RayHitK<K>& ray,
++ IntersectContext* context,
++ const vuint<M>& geomIDs,
++ const vuint<M>& primIDs,
++ size_t i)
++ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {}
++
++ template<typename Hit>
++ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
++ {
++ Scene* scene MAYBE_UNUSED = context->scene;
++
++ vfloat<K> u, v, t;
++ Vec3vf<K> Ng;
++ vbool<K> 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<K> h(context->user,geomID,primID,u,v,Ng);
++ const vfloat<K> old_t = ray.tfar;
++ ray.tfar = select(valid,t,ray.tfar);
++ const vbool<K> 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<K>::store(valid,&ray.tfar,t);
++ vfloat<K>::store(valid,&ray.Ng.x,Ng.x);
++ vfloat<K>::store(valid,&ray.Ng.y,Ng.y);
++ vfloat<K>::store(valid,&ray.Ng.z,Ng.z);
++ vfloat<K>::store(valid,&ray.u,u);
++ vfloat<K>::store(valid,&ray.v,v);
++ vuint<K>::store(valid,&ray.primID,primID);
++ vuint<K>::store(valid,&ray.geomID,geomID);
++ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid);
++ return valid;
++ }
++ };
++
++ template<int M, int K, bool filter>
++ struct OccludedKEpilogM
++ {
++ vbool<K>& valid0;
++ RayK<K>& ray;
++ IntersectContext* context;
++ const vuint<M>& geomIDs;
++ const vuint<M>& primIDs;
++ const size_t i;
++
++ __forceinline OccludedKEpilogM(vbool<K>& valid0,
++ RayK<K>& ray,
++ IntersectContext* context,
++ const vuint<M>& geomIDs,
++ const vuint<M>& primIDs,
++ size_t i)
++ : valid0(valid0), ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {}
++
++ template<typename Hit>
++ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
++ {
++ vbool<K> 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<K> u, v, t;
++ Vec3vf<K> Ng;
++ std::tie(u,v,t,Ng) = hit();
++ HitK<K> h(context->user,geomID,primID,u,v,Ng);
++ const vfloat<K> 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<int M, int K, bool filter>
++ struct IntersectKEpilogMU
++ {
++ RayHitK<K>& ray;
++ IntersectContext* context;
++ const unsigned int geomID;
++ const unsigned int primID;
++
++ __forceinline IntersectKEpilogMU(RayHitK<K>& ray,
++ IntersectContext* context,
++ const unsigned int geomID,
++ const unsigned int primID)
++ : ray(ray), context(context), geomID(geomID), primID(primID) {}
++
++ template<typename Hit>
++ __forceinline vbool<K> operator() (const vbool<K>& valid_org, const Hit& hit) const
++ {
++ vbool<K> valid = valid_org;
++ vfloat<K> u, v, t;
++ Vec3vf<K> 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<K> h(context->user,geomID,primID,u,v,Ng);
++ const vfloat<K> old_t = ray.tfar;
++ ray.tfar = select(valid,t,ray.tfar);
++ const vbool<K> 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<K>::store(valid,&ray.tfar,t);
++ vfloat<K>::store(valid,&ray.Ng.x,Ng.x);
++ vfloat<K>::store(valid,&ray.Ng.y,Ng.y);
++ vfloat<K>::store(valid,&ray.Ng.z,Ng.z);
++ vfloat<K>::store(valid,&ray.u,u);
++ vfloat<K>::store(valid,&ray.v,v);
++ vuint<K>::store(valid,&ray.primID,primID);
++ vuint<K>::store(valid,&ray.geomID,geomID);
++ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid);
++ return valid;
++ }
++ };
++
++ template<int M, int K, bool filter>
++ struct OccludedKEpilogMU
++ {
++ vbool<K>& valid0;
++ RayK<K>& ray;
++ IntersectContext* context;
++ const unsigned int geomID;
++ const unsigned int primID;
++
++ __forceinline OccludedKEpilogMU(vbool<K>& valid0,
++ RayK<K>& ray,
++ IntersectContext* context,
++ const unsigned int geomID,
++ const unsigned int primID)
++ : valid0(valid0), ray(ray), context(context), geomID(geomID), primID(primID) {}
++
++ template<typename Hit>
++ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
++ {
++ vbool<K> 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<K> u, v, t;
++ Vec3vf<K> Ng;
++ std::tie(u,v,t,Ng) = hit();
++ HitK<K> h(context->user,geomID,primID,u,v,Ng);
++ const vfloat<K> 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<int M, int K, bool filter>
++ struct Intersect1KEpilogM
++ {
++ RayHitK<K>& ray;
++ size_t k;
++ IntersectContext* context;
++ const vuint<M>& geomIDs;
++ const vuint<M>& primIDs;
++
++ __forceinline Intersect1KEpilogM(RayHitK<K>& ray, size_t k,
++ IntersectContext* context,
++ const vuint<M>& geomIDs,
++ const vuint<M>& primIDs)
++ : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
++
++ template<typename Hit>
++ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
++ {
++ Scene* scene MAYBE_UNUSED = context->scene;
++ vbool<M> valid = valid_i;
++ hit.finalize();
++ size_t i = select_min(valid,hit.vt);
++ assert(i<M);
++ 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);
++ assert(i<M);
++ 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[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<M);
++ const Vec2f uv = hit.uv(i);
++ HitK<K> 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<K>(1<<k),geometry,ray,context,h));
++ if (!found) ray.tfar[k] = old_t;
++ foundhit = foundhit | found;
++ clear(valid,i);
++ valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value
++ continue;
++ }
++ }
++ #endif
++ break;
++ }
++ #endif
++ assert(i<M);
++ /* update hit information */
++ const Vec2f uv = hit.uv(i);
++ ray.tfar[k] = hit.t(i);
++ ray.Ng.x[k] = hit.vNg.x[i];
++ ray.Ng.y[k] = hit.vNg.y[i];
++ ray.Ng.z[k] = hit.vNg.z[i];
++ ray.u[k] = uv.x;
++ ray.v[k] = uv.y;
++ ray.primID[k] = primIDs[i];
++ ray.geomID[k] = geomID;
++ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
++ return true;
++ }
++ };
++
++ template<int M, int K, bool filter>
++ struct Occluded1KEpilogM
++ {
++ RayK<K>& ray;
++ size_t k;
++ IntersectContext* context;
++ const vuint<M>& geomIDs;
++ const vuint<M>& primIDs;
++
++ __forceinline Occluded1KEpilogM(RayK<K>& ray, size_t k,
++ IntersectContext* context,
++ const vuint<M>& geomIDs,
++ const vuint<M>& primIDs)
++ : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
++
++ template<typename Hit>
++ __forceinline bool operator() (const vbool<M>& 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<M> 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<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
++ if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true;
++ ray.tfar[k] = old_t;
++ m=btc(m,i);
++ continue;
++ }
++ }
++ #endif
++ break;
++ }
++ #endif
++ return true;
++ }
++ };
++
++ template<int M, int K, bool filter>
++ struct Intersect1KEpilogMU
++ {
++ RayHitK<K>& ray;
++ size_t k;
++ IntersectContext* context;
++ const unsigned int geomID;
++ const unsigned int primID;
++
++ __forceinline Intersect1KEpilogMU(RayHitK<K>& 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<typename Hit>
++ __forceinline bool operator() (const vbool<M>& 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<M> 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<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
++ const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
++ if (!found) ray.tfar[k] = old_t;
++ foundhit = foundhit | found;
++ clear(valid,i);
++ valid &= hit.vt <= ray.tfar[k]; // 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[k] = hit.t(i);
++ ray.Ng.x[k] = Ng.x;
++ ray.Ng.y[k] = Ng.y;
++ ray.Ng.z[k] = Ng.z;
++ ray.u[k] = uv.x;
++ ray.v[k] = uv.y;
++ ray.primID[k] = primID;
++ ray.geomID[k] = geomID;
++ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
++ return true;
++ }
++ };
++
++ template<int M, int K, bool filter>
++ struct Occluded1KEpilogMU
++ {
++ RayK<K>& ray;
++ size_t k;
++ IntersectContext* context;
++ const unsigned int geomID;
++ const unsigned int primID;
++
++ __forceinline Occluded1KEpilogMU(RayK<K>& 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<typename Hit>
++ __forceinline bool operator() (const vbool<M>& 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<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
++ if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true;
++ ray.tfar[k] = old_t;
++ }
++ return false;
++ }
++ }
++ #endif
++ return true;
++ }
++ };
++ }
++ }