commit 695c9179ef4c54fe26b7690c373dc21f981e3698
parent 8e782af7a7bef563c739a67806fec29bb643d92a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 1 Oct 2019 09:37:44 +0200
Add the s3d_scene_view_create2 function
This function provides a new parameter that allow to configure the
quality and the properties of the acceleration structure used by the
ray-tracing procedure.
Diffstat:
5 files changed, 161 insertions(+), 16 deletions(-)
diff --git a/src/s3d.h b/src/s3d.h
@@ -169,6 +169,42 @@ enum s3d_scene_view_flag {
* intersects a shape or not */
#define S3D_HIT_NONE(Hit) ((Hit)->distance >= FLT_MAX)
+/* Quality of the partitioning data structure used tu accelerate the
+ * ray-tracing procedure. The lowest the structure quality is, the fastest it
+ * is built. On the counterpart, a weak structure quality means that the
+ * partitioning of the geometry is sub-optimal, leading to lower ray-tracing
+ * performances. */
+enum s3d_rt_accel_struct_quality {
+ S3D_RT_ACCEL_STRUCT_QUALITY_LOW,
+ S3D_RT_ACCEL_STRUCT_QUALITY_MEDIUM,
+ S3D_RT_ACCEL_STRUCT_QUALITY_HIGH
+};
+
+/* Define the properties of the partitioning data structure used to accelerate
+ * the ray-tracing procedure. */
+enum s3d_rt_accel_struct_flag {
+ /* Avoid optimisations that reduce arithmetic accuracy */
+ S3D_RT_ACCEL_STRUCT_FLAG_ROBUST = BIT(0),
+ /* Improve the building performances of the acceleration structure for
+ * dynamic scenes */
+ S3D_RT_ACCEL_STRUCT_FLAG_DYNAMIC = BIT(1),
+ /* Reduce the memory consumption of the acceleration structure */
+ S3D_RT_ACCEL_STRUCT_FLAG_COMPACT = BIT(2)
+};
+
+/* Configuration of the acceleration data structure used to accelerate the
+ * ray-tracing procedure */
+struct s3d_rt_accel_struct_conf {
+ enum s3d_rt_accel_struct_quality quality;
+ int mask; /* combination of s3d_rt_accel_struct_flag */
+};
+#define S3D_RT_ACCEL_STRUCT_CONF_DEFAULT__ { \
+ S3D_RT_ACCEL_STRUCT_QUALITY_MEDIUM, \
+ S3D_RT_ACCEL_STRUCT_FLAG_ROBUST \
+}
+static const struct s3d_rt_accel_struct_conf S3D_RT_ACCEL_STRUCT_CONF_DEFAULT =
+ S3D_RT_ACCEL_STRUCT_CONF_DEFAULT__;
+
/* Filter function data type. One can define such function to discard
* intersections along a ray with respect to user defined criteria, e.g.:
* masked/transparent primitive, etc. Return 0 or the intersection is not
@@ -283,6 +319,15 @@ s3d_scene_view_create
struct s3d_scene_view** scnview);
S3D_API res_T
+s3d_scene_view_create2
+ (struct s3d_scene* scn,
+ const int mask, /* Combination of s3d_scene_view_flag */
+ /* Ignored if (mask & S3D_TRACE) == 0
+ * NULL <=> use S3D_RT_ACCEL_STRUCT_CONF_DEFAULT */
+ const struct s3d_rt_accel_struct_conf* cfg,
+ struct s3d_scene_view** scnview);
+
+S3D_API res_T
s3d_scene_view_ref_get
(struct s3d_scene_view* scnview);
diff --git a/src/s3d_geometry.c b/src/s3d_geometry.c
@@ -167,6 +167,7 @@ geometry_create
geom->data.mesh = NULL;
geom->rtc = NULL;
geom->rtc_id = RTC_INVALID_GEOMETRY_ID;
+ geom->rtc_build_quality = RTC_BUILD_QUALITY_MEDIUM;
exit:
*out_geom = geom;
diff --git a/src/s3d_geometry.h b/src/s3d_geometry.h
@@ -58,6 +58,7 @@ enum embree_attrib {
struct geometry {
unsigned name; /* Client side identifier */
RTCGeometry rtc; /* Embree geometry */
+ enum RTCBuildQuality rtc_build_quality; /* BVH build quality */
unsigned rtc_id; /* Embree geometry identifier */
unsigned scene_prim_id_offset; /* Offset from local to scene prim_id */
diff --git a/src/s3d_scene_view.c b/src/s3d_scene_view.c
@@ -232,21 +232,72 @@ hit_setup
if(flip_surface) f3_minus(hit->normal, hit->normal);
}
+static INLINE enum RTCBuildQuality
+rt_accel_struct_quality_to_rtc_build_quality
+ (enum s3d_rt_accel_struct_quality quality)
+{
+ enum RTCBuildQuality rtc_quality = RTC_BUILD_QUALITY_MEDIUM;
+ switch(quality) {
+ case S3D_RT_ACCEL_STRUCT_QUALITY_LOW:
+ rtc_quality = RTC_BUILD_QUALITY_LOW;
+ break;
+ case S3D_RT_ACCEL_STRUCT_QUALITY_MEDIUM:
+ rtc_quality = RTC_BUILD_QUALITY_MEDIUM;
+ break;
+ case S3D_RT_ACCEL_STRUCT_QUALITY_HIGH:
+ rtc_quality = RTC_BUILD_QUALITY_HIGH;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ return rtc_quality;
+}
+
+static INLINE int
+rt_accel_struct_mask_to_rtc_scene_flags(const int mask)
+{
+ int rtc_scene_flags = 0;
+ if(mask & S3D_RT_ACCEL_STRUCT_FLAG_ROBUST)
+ rtc_scene_flags |= RTC_SCENE_FLAG_ROBUST;
+ if(mask & S3D_RT_ACCEL_STRUCT_FLAG_DYNAMIC)
+ rtc_scene_flags |= RTC_SCENE_FLAG_DYNAMIC;
+ if(mask & S3D_RT_ACCEL_STRUCT_FLAG_COMPACT)
+ rtc_scene_flags |= RTC_SCENE_FLAG_COMPACT;
+ return rtc_scene_flags;
+}
+
static res_T
embree_geometry_register
(struct s3d_scene_view* scnview,
- struct geometry* geom)
+ struct geometry* geom,
+ const struct s3d_rt_accel_struct_conf* rt_accel_struct_conf)
{
- ASSERT(scnview && geom);
+ enum RTCBuildQuality rtc_build_quality = RTC_BUILD_QUALITY_MEDIUM;
+ ASSERT(scnview && geom && rt_accel_struct_conf);
+
+ rtc_build_quality = rt_accel_struct_quality_to_rtc_build_quality
+ (rt_accel_struct_conf->quality);
/* Create the Embree geometry if it is not valid */
if(geom->rtc != NULL) {
- if(geom->type == GEOM_INSTANCE) {
- /* If the geometry is an instance one have to update it if the
- * instantiated geometry was updated. Currently, we have no simple way to
- * know if the geometry was upd or not so we simply force the update. */
- rtcCommitGeometry(geom->rtc);
- scnview->rtc_scn_update = 1;
+ switch(geom->type) {
+ case GEOM_MESH:
+ if(geom->rtc_build_quality != rtc_build_quality) {
+ /* Update the build quality of the geometry */
+ rtcSetGeometryBuildQuality(geom->rtc, rtc_build_quality);
+ rtcCommitGeometry(geom->rtc);
+ geom->rtc_build_quality = rtc_build_quality;
+ scnview->rtc_scn_update = 1;
+ }
+ break;
+ case GEOM_INSTANCE:
+ /* If the geometry is an instance one have to update it if the
+ * instantiated geometry was updated. Currently, we have no simple way to
+ * know if the geometry was upd or not so we simply force the update. */
+ rtcCommitGeometry(geom->rtc);
+ scnview->rtc_scn_update = 1;
+ break;
+ case GEOM_SPHERE: /* Do nothing */ break;
+ default: FATAL("Unreachable code\n"); break;
}
} else {
switch(geom->type) {
@@ -273,6 +324,12 @@ embree_geometry_register
if(geom->rtc == NULL)
return RES_UNKNOWN_ERR;
+ if(geom->type == GEOM_MESH) {
+ /* Set the build quality of the geometry */
+ rtcSetGeometryBuildQuality(geom->rtc, rtc_build_quality);
+ geom->rtc_build_quality = rtc_build_quality;
+ }
+
/* Set the Star-3D representation of the geometry to the Embree geometry */
rtcSetGeometryUserData(geom->rtc, geom);
@@ -385,13 +442,22 @@ embree_geometry_setup_transform
}
static INLINE res_T
-scene_view_setup_embree(struct s3d_scene_view* scnview)
+scene_view_setup_embree
+ (struct s3d_scene_view* scnview,
+ const struct s3d_rt_accel_struct_conf* rt_accel_struct_conf)
{
struct htable_geom_iterator it, end;
int rtc_outdated = 0;
+ int rtc_scn_flags = 0;
+ enum RTCBuildQuality rtc_scn_build_quality = 0;
res_T res = RES_OK;
ASSERT(scnview);
+ rtc_scn_flags = rt_accel_struct_mask_to_rtc_scene_flags
+ (rt_accel_struct_conf->mask);
+ rtc_scn_build_quality = rt_accel_struct_quality_to_rtc_build_quality
+ (rt_accel_struct_conf->quality);
+
/* The rtc_scn could be already allocated since the scene views are cached */
if(!scnview->rtc_scn) {
scnview->rtc_scn = rtcNewScene(scnview->scn->dev->rtc);
@@ -399,8 +465,20 @@ scene_view_setup_embree(struct s3d_scene_view* scnview)
res = rtc_error_to_res_T(rtcGetDeviceError(scnview->scn->dev->rtc));
goto error;
}
- rtcSetSceneFlags
- (scnview->rtc_scn, RTC_SCENE_FLAG_ROBUST | RTC_SCENE_FLAG_DYNAMIC);
+ rtcSetSceneFlags(scnview->rtc_scn, rtc_scn_flags);
+ scnview->rtc_scn_flags = rtc_scn_flags;
+ rtc_outdated = 1;
+ }
+
+ /* Check if the scene flags were updated */
+ if(scnview->rtc_scn_flags != rtc_scn_flags) {
+ rtcSetSceneFlags(scnview->rtc_scn, rtc_scn_flags);
+ rtc_outdated = 1;
+ }
+
+ /* Check if the build quality was updated */
+ if(scnview->rtc_scn_build_quality != rtc_scn_build_quality) {
+ rtcSetSceneBuildQuality(scnview->rtc_scn, rtc_scn_build_quality);
rtc_outdated = 1;
}
@@ -419,7 +497,7 @@ scene_view_setup_embree(struct s3d_scene_view* scnview)
rtc_outdated = 1;
/* Register the embree geometry */
- res = embree_geometry_register(scnview, geom);
+ res = embree_geometry_register(scnview, geom, rt_accel_struct_conf);
if(res != RES_OK) goto error;
/* Flush the embree geometry states */
@@ -936,12 +1014,13 @@ scene_view_compute_volume
static res_T
scene_view_sync
(struct s3d_scene_view* scnview,
- const int mask)
+ const int mask,
+ const struct s3d_rt_accel_struct_conf* rt_accel_struct_conf)
{
struct htable_shape_iterator it, end;
res_T res = RES_OK;
- ASSERT(scnview);
+ ASSERT(scnview && rt_accel_struct_conf);
ASSERT((mask & (S3D_TRACE|S3D_SAMPLE|S3D_GET_PRIMITIVE)) != 0);
/* Commit the scene shape to the scnview */
@@ -971,7 +1050,7 @@ scene_view_sync
/* Setup the scene for the S3D_TRACE scnview */
if((mask & S3D_TRACE) != 0) {
- res = scene_view_setup_embree(scnview);
+ res = scene_view_setup_embree(scnview, rt_accel_struct_conf);
if(res != RES_OK) goto error;
}
/* Setup the scene for the S3D_SAMPLE scnview */
@@ -1019,6 +1098,7 @@ scene_view_create(struct s3d_scene* scn, struct s3d_scene_view** out_scnview)
f3_splat(scnview->lower, FLT_MAX);
f3_splat(scnview->upper,-FLT_MAX);
ref_init(&scnview->ref);
+ scnview->rtc_scn_build_quality = RTC_BUILD_QUALITY_MEDIUM;
CLBK_INIT(&scnview->on_shape_detach_cb);
CLBK_SETUP(&scnview->on_shape_detach_cb, on_shape_detach, scnview);
@@ -1104,7 +1184,19 @@ s3d_scene_view_create
const int mask,
struct s3d_scene_view** out_scnview)
{
+ return s3d_scene_view_create2
+ (scn, mask, &S3D_RT_ACCEL_STRUCT_CONF_DEFAULT, out_scnview);
+}
+
+res_T
+s3d_scene_view_create2
+ (struct s3d_scene* scn,
+ const int mask,
+ const struct s3d_rt_accel_struct_conf* cfg,
+ struct s3d_scene_view** out_scnview)
+{
struct s3d_scene_view* scnview = NULL;
+ const struct s3d_rt_accel_struct_conf* rt_accel_struct_conf = cfg;
res_T res = RES_OK;
if(!scn || !out_scnview) {
@@ -1112,6 +1204,10 @@ s3d_scene_view_create
goto error;
}
+ if(!rt_accel_struct_conf && (mask & S3D_TRACE)) {
+ rt_accel_struct_conf = &S3D_RT_ACCEL_STRUCT_CONF_DEFAULT;
+ }
+
if(!(mask & S3D_TRACE)
&& !(mask & S3D_SAMPLE)
&& !(mask & S3D_GET_PRIMITIVE)) {
@@ -1123,7 +1219,7 @@ s3d_scene_view_create
res = scene_view_create(scn, &scnview);
if(res != RES_OK) goto error;
- res = scene_view_sync(scnview, mask);
+ res = scene_view_sync(scnview, mask, rt_accel_struct_conf);
if(res != RES_OK) goto error;
exit:
diff --git a/src/s3d_scene_view_c.h b/src/s3d_scene_view_c.h
@@ -91,6 +91,8 @@ struct s3d_scene_view {
int mask; /* Combination of enum s3d_scene_view_flag */
int rtc_scn_update; /* Define if Embree geometries were deleted/added */
int rtc_commit; /* Define whether or not the Embree scene was committed */
+ int rtc_scn_flags; /* Flags used to configure the Embree scene */
+ enum RTCBuildQuality rtc_scn_build_quality; /* Build quality of the BVH */
RTCScene rtc_scn; /* Embree scene */
ref_T ref;