From db0951dc40c1e786c7554be7b9af30907b73ff40 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Sun, 19 Nov 2023 14:00:10 -0700 Subject: [PATCH] light: support embree4 in addition to 3 --- CMakeLists.txt | 5 +++ include/light/trace_embree.hh | 29 ++++++++++++++- light/CMakeLists.txt | 2 -- light/trace_embree.cc | 68 ++++++++++++++++++++++++++++------- lightpreview/CMakeLists.txt | 1 - tests/CMakeLists.txt | 1 - 6 files changed, 88 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3c33934..43027383 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,6 +145,11 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15) find_package(TBB REQUIRED) +find_package(embree REQUIRED) +if (embree_VERSION_MAJOR EQUAL 4) + add_compile_definitions(HAVE_EMBREE4) +endif() + set(TEST_QUAKE_MAP_EXPORT_DIR "" CACHE PATH "When running unit tests, export Quake maps to this directory (useful for testing in game)") set(TEST_QUAKE2_MAP_EXPORT_DIR "" CACHE PATH "When running unit tests, export Quake 2 maps to this directory (useful for testing in game)") set(TEST_HEXEN2_MAP_EXPORT_DIR "" CACHE PATH "When running unit tests, export Hexen 2 maps to this directory (useful for testing in game)") diff --git a/include/light/trace_embree.hh b/include/light/trace_embree.hh index 69333d97..01dd3f80 100644 --- a/include/light/trace_embree.hh +++ b/include/light/trace_embree.hh @@ -100,8 +100,13 @@ public: inline void clearPushedRays() { _numrays = 0; } }; +#ifdef HAVE_EMBREE4 +#include +#include +#else #include #include +#endif extern RTCScene scene; @@ -139,13 +144,22 @@ inline RTCRayHit SetupRay(unsigned rayindex, const qvec3d &start, const qvec3d & class light_t; -struct ray_source_info : public RTCIntersectContext +struct ray_source_info : public +#ifdef HAVE_EMBREE4 + RTCRayQueryContext +#else + RTCIntersectContext +#endif { raystream_embree_common_t *raystream; // may be null if this ray is not from a ray stream const modelinfo_t *self; int shadowmask; ray_source_info(raystream_embree_common_t *raystream_, const modelinfo_t *self_, int shadowmask_); +#ifdef HAVE_EMBREE4 + RTCIntersectArguments setup_intersection_arguments(); + RTCOccludedArguments setup_occluded_arguments(); +#endif }; struct triinfo @@ -238,7 +252,14 @@ public: return; ray_source_info ctx2(this, self, shadowmask); + +#ifdef HAVE_EMBREE4 + RTCIntersectArguments embree4_args = ctx2.setup_intersection_arguments(); + for (int i = 0; i < _numrays; ++i) + rtcIntersect1(scene, &_rays[i], &embree4_args); +#else rtcIntersect1M(scene, &ctx2, _rays.data(), _numrays, sizeof(_rays[0])); +#endif } inline qvec3d getPushedRayDir(size_t j) { return {_rays[j].ray.dir_x, _rays[j].ray.dir_y, _rays[j].ray.dir_z}; } @@ -312,7 +333,13 @@ public: return; ray_source_info ctx2(this, self, shadowmask); +#ifdef HAVE_EMBREE4 + RTCOccludedArguments embree4_args = ctx2.setup_occluded_arguments(); + for (int i = 0; i < _numrays; ++i) + rtcOccluded1(scene, &_rays[i], &embree4_args); +#else rtcOccluded1M(scene, &ctx2, _rays.data(), _numrays, sizeof(_rays[0])); +#endif } inline bool getPushedRayOccluded(size_t j) { return (_rays[j].tfar < 0.0f); } diff --git a/light/CMakeLists.txt b/light/CMakeLists.txt index 2e4646ab..9e6098df 100644 --- a/light/CMakeLists.txt +++ b/light/CMakeLists.txt @@ -24,8 +24,6 @@ set(LIGHT_SOURCES surflight.cc ${LIGHT_INCLUDES}) -FIND_PACKAGE(embree 3.0 REQUIRED) - if (embree_FOUND) MESSAGE(STATUS "Embree library found: ${EMBREE_LIBRARY}") INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS}) diff --git a/light/trace_embree.cc b/light/trace_embree.cc index 51ae85a6..5a77d10c 100644 --- a/light/trace_embree.cc +++ b/light/trace_embree.cc @@ -289,14 +289,13 @@ inline qvec3f Embree_RayEndpoint(RTCRayN *ray, const qvec3f &dir, size_t N, size return org + (dir * tfar); } -static void AddGlassToRay(RTCIntersectContext *context, unsigned rayIndex, float opacity, const qvec3d &glasscolor); -static void AddDynamicOccluderToRay(RTCIntersectContext *context, unsigned rayIndex, int style); +static void AddGlassToRay(ray_source_info *context, unsigned rayIndex, float opacity, const qvec3d &glasscolor); +static void AddDynamicOccluderToRay(ray_source_info *context, unsigned rayIndex, int style); // called to evaluate transparency static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args) { int *const valid = args->valid; - RTCIntersectContext *const context = args->context; struct RTCRayN *const ray = args->ray; struct RTCHitN *const potentialHit = args->hit; const unsigned int N = args->N; @@ -304,7 +303,7 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args) const int VALID = -1; const int INVALID = 0; - const ray_source_info *rsi = static_cast(context); + ray_source_info *rsi = static_cast(args->context); for (size_t i = 0; i < N; i++) { if (valid[i] != VALID) { @@ -359,7 +358,7 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args) const int style = hit_triinfo.switchshadstyle; - AddDynamicOccluderToRay(context, rayIndex, style); + AddDynamicOccluderToRay(rsi, rayIndex, style); // reject hit valid[i] = INVALID; @@ -391,7 +390,7 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args) // only pick up the color of the glass on the _exiting_ side of the glass. // (we currently trace "backwards", from surface point --> light source) if (raySurfaceCosAngle < 0) { - AddGlassToRay(context, rayIndex, alpha, sample.xyz() * (1.0 / 255.0)); + AddGlassToRay(rsi, rayIndex, alpha, sample.xyz() * (1.0 / 255.0)); } // reject hit @@ -419,14 +418,13 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args) static void PerRay_FilterFuncN(const struct RTCFilterFunctionNArguments *args) { int *const valid = args->valid; - RTCIntersectContext *const context = args->context; struct RTCHitN *const potentialHit = args->hit; const unsigned int N = args->N; const int VALID = -1; const int INVALID = 0; - auto *rsi = static_cast(context); + auto *rsi = static_cast(args->context); for (size_t i = 0; i < N; i++) { if (valid[i] != VALID) { @@ -656,9 +654,16 @@ void Embree_TraceInit(const mbsp_t *bsp) logging::funcprint("Embree version: {}.{}.{}\n", ver_maj, ver_min, ver_pat); scene = rtcNewScene(device); +#ifdef HAVE_EMBREE4 + // necessary for RTCOccludedArguments::filter and RTCIntersectArguments::filter + // to work, which we use (see: ray_source_info::setup_intersection_arguments() and + // ray_source_info::setup_occluded_arguments()) + rtcSetSceneFlags(scene, RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS); +#else // we're using RTCIntersectContext::filter so it's required that we set // RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION rtcSetSceneFlags(scene, RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION); +#endif rtcSetSceneBuildQuality(scene, RTC_BUILD_QUALITY_HIGH); skygeom = CreateGeometry(bsp, device, scene, skyfaces); solidgeom = CreateGeometry(bsp, device, scene, solidfaces); @@ -677,9 +682,8 @@ void Embree_TraceInit(const mbsp_t *bsp) logging::print("\t{} shadow-casting skip faces\n", skipwindings.size()); } -static void AddGlassToRay(RTCIntersectContext *context, unsigned rayIndex, float opacity, const qvec3d &glasscolor) +static void AddGlassToRay(ray_source_info *ctx, unsigned rayIndex, float opacity, const qvec3d &glasscolor) { - ray_source_info *ctx = static_cast(context); raystream_embree_common_t *rs = ctx->raystream; if (rs == nullptr) { @@ -698,9 +702,8 @@ static void AddGlassToRay(RTCIntersectContext *context, unsigned rayIndex, float rs->_ray_glass_opacity[rayIndex] = opacity; } -static void AddDynamicOccluderToRay(RTCIntersectContext *context, unsigned rayIndex, int style) +static void AddDynamicOccluderToRay(ray_source_info *ctx, unsigned rayIndex, int style) { - ray_source_info *ctx = static_cast(context); raystream_embree_common_t *rs = ctx->raystream; if (rs != nullptr) { @@ -713,12 +716,51 @@ ray_source_info::ray_source_info(raystream_embree_common_t *raystream_, const mo self(self_), shadowmask(shadowmask_) { +#ifdef HAVE_EMBREE4 + rtcInitRayQueryContext(this); +#else rtcInitIntersectContext(this); - flags = RTC_INTERSECT_CONTEXT_FLAG_COHERENT; if (shadowmask != CHANNEL_MASK_DEFAULT) { // non-default shadow mask means we have to use the slow path filter = PerRay_FilterFuncN; } +#endif } + +#ifdef HAVE_EMBREE4 +RTCIntersectArguments ray_source_info::setup_intersection_arguments() +{ + RTCIntersectArguments result; + + rtcInitIntersectArguments(&result); + if (shadowmask != CHANNEL_MASK_DEFAULT) { + // non-default shadow mask means we have to use the slow path + result.filter = PerRay_FilterFuncN; + result.flags = static_cast(result.flags | + RTC_RAY_QUERY_FLAG_INVOKE_ARGUMENT_FILTER); + } + + result.context = this; + + return result; +} + +RTCOccludedArguments ray_source_info::setup_occluded_arguments() +{ + RTCOccludedArguments result; + + rtcInitOccludedArguments(&result); + if (shadowmask != CHANNEL_MASK_DEFAULT) { + // non-default shadow mask means we have to use the slow path + result.filter = PerRay_FilterFuncN; + result.flags = static_cast(result.flags | + RTC_RAY_QUERY_FLAG_INVOKE_ARGUMENT_FILTER); + } + + result.context = this; + + return result; +} +#endif \ No newline at end of file diff --git a/lightpreview/CMakeLists.txt b/lightpreview/CMakeLists.txt index f0ec5e31..ee7b8c15 100644 --- a/lightpreview/CMakeLists.txt +++ b/lightpreview/CMakeLists.txt @@ -19,7 +19,6 @@ add_executable(lightpreview set_target_properties(lightpreview PROPERTIES WIN32_EXECUTABLE YES) -find_package(embree 3.0 REQUIRED) INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS}) # HACK: Windows embree .dll's from https://github.com/embree/embree/releases ship with a tbb12.dll diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8056ba96..a82a4310 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,7 +17,6 @@ add_executable(tests benchmark.cc test_bsputil.cc) -find_package(embree 3.0 REQUIRED) INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS}) # HACK: Windows embree .dll's from https://github.com/embree/embree/releases ship with a tbb12.dll