commit 6eb8e09b01b17b98d304e0565025afd718993552
parent ee8cf0567a598920f9710039864f7c936880d9f4
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 25 Jul 2016 09:20:30 +0200
Allow multiple scene sessions on the same scene
A scene can have several active sessions independently of the instancing
feature.
Diffstat:
4 files changed, 254 insertions(+), 180 deletions(-)
diff --git a/src/s3d_geometry.h b/src/s3d_geometry.h
@@ -44,11 +44,22 @@ enum geometry_type {
GEOM_NONE = GEOM_TYPES_COUNT__
};
+enum embree_attrib {
+ EMBREE_ENABLE = BIT(0),
+ EMBREE_FILTER_FUNCTION = BIT(1),
+ EMBREE_INDICES = BIT(2),
+ EMBREE_TRANSFORM = BIT(4),
+ EMBREE_VERTICES = BIT(5)
+};
+
/* Backend geometry */
struct geometry {
unsigned name; /* Client side identifier */
unsigned irtc; /* Embree identifier */
unsigned scene_prim_id_offset; /* Offset from local to scene prim_id */
+
+ int embree_outdated_mask; /* Combination of embree_attrib */
+
char flip_surface; /* Is the geometry surface flipped? */
char is_enabled; /* Is the geometry enabled? */
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -42,14 +42,13 @@
#include <algorithm>
-/* Flag used to define session enabled on instantiated scene */
-#define S3D_INSTANCE (BIT(sizeof(int)*8 - 1))
-
struct ray_extended : public RTCRay {
struct s3d_scene* scene;
void* data; /* User defined data */
};
+#define INTERNAL_SESSION ((unsigned char)(-1))
+
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -146,49 +145,8 @@ filter_wrapper(void* user_ptr, RTCRay& ray)
static res_T
scene_sync
(struct s3d_scene* scn,
- const int mask);/* combination of s3d_session_flag & S3D_INSTANCE */
-
-static INLINE void
-scene_geometry_flush_enable_state
- (struct s3d_scene* scn,
- struct geometry* geom, /* Cached geometry */
- const struct s3d_shape* shape) /* New shape */
-{
- ASSERT(scn && geom && shape);
- if(geom->is_enabled == shape->is_enabled)
- return;
-
- geom->is_enabled = shape->is_enabled;
- if(geom->is_enabled) {
- rtcEnable(scn->rtc_scn, geom->irtc);
- } else {
- rtcDisable(scn->rtc_scn, geom->irtc);
- }
- scn->is_rtc_scn_outdated = 1;
-}
-
-static INLINE void
-scene_geometry_flush_filter_function
- (struct s3d_scene* scn,
- struct geometry* geom, /* Cached geometry */
- const struct s3d_shape* shape)
-{
- ASSERT(scn && geom && shape && geom->irtc != RTC_INVALID_GEOMETRY_ID);
- ASSERT(shape->type == GEOM_MESH);
-
- if(geom->data.mesh->filter.func == shape->data.mesh->filter.func
- && geom->data.mesh->filter.data == shape->data.mesh->filter.data)
- return; /* Up to date */
-
- geom->data.mesh->filter = shape->data.mesh->filter;
- if(!geom->data.mesh->filter.func) {
- rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, NULL);
- } else {
- rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, filter_wrapper);
- rtcSetUserData(scn->rtc_scn, geom->irtc, &geom->data.mesh->filter);
- }
- scn->is_rtc_scn_outdated = 1;
-}
+ const int mask, /* Combination of s3d_session_flag */
+ const int internal); /* Is the synchronized session internal? */
static res_T
scene_register_embree_geometry(struct s3d_scene* scn, struct geometry* geom)
@@ -210,8 +168,6 @@ scene_register_embree_geometry(struct s3d_scene* scn, struct geometry* geom)
}
if(geom->irtc == RTC_INVALID_GEOMETRY_ID)
return RES_UNKNOWN_ERR;
-
- scn->is_rtc_scn_outdated = 1;
}
if(geom->irtc >= darray_geom_size_get(&scn->embree2geoms)) {
@@ -222,52 +178,172 @@ scene_register_embree_geometry(struct s3d_scene* scn, struct geometry* geom)
return res;
}
}
- geometry_ref_get(geom);
darray_geom_data_get(&scn->embree2geoms)[geom->irtc] = geom;
return RES_OK;
}
static INLINE void
-scene_geometry_flush_positions(struct s3d_scene* scn, struct geometry* geom)
+scene_setup_embree_geometry_positions
+ (struct s3d_scene* scn, struct geometry* geom)
{
ASSERT(scn && geom && geom->type == GEOM_MESH);
ASSERT(geom->irtc != RTC_INVALID_GEOMETRY_ID);
rtcSetBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER,
mesh_get_pos(geom->data.mesh), 0, sizeof(float[3]));
rtcUpdateBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER);
- scn->is_rtc_scn_outdated = 1;
}
static INLINE void
-scene_geometry_flush_indices(struct s3d_scene* scn, struct geometry* geom)
+scene_setup_embree_geometry_indices
+ (struct s3d_scene* scn, struct geometry* geom)
{
ASSERT(scn && geom && geom->type == GEOM_MESH);
ASSERT(geom->irtc != RTC_INVALID_GEOMETRY_ID);
rtcSetBuffer(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER,
mesh_get_ids(geom->data.mesh), 0, sizeof(uint32_t[3]));
rtcUpdateBuffer(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER);
- scn->is_rtc_scn_outdated = 1;
}
-static void
-scene_session_clear(struct s3d_scene* scn)
+static INLINE void
+scene_setup_embree_geometry_enable_state
+ (struct s3d_scene* scn, struct geometry* geom)
{
- struct geometry** geoms;
- size_t ngeoms;
- size_t i;
+ ASSERT(scn && geom);
+ if(geom->is_enabled) {
+ rtcEnable(scn->rtc_scn, geom->irtc);
+ } else {
+ rtcDisable(scn->rtc_scn, geom->irtc);
+ }
+}
+
+static INLINE void
+scene_setup_embree_geometry_filter_function
+ (struct s3d_scene* scn, struct geometry* geom)
+{
+ ASSERT(scn && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ ASSERT(geom->type == GEOM_MESH);
+
+ if(!geom->data.mesh->filter.func) {
+ rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, NULL);
+ } else {
+ rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, filter_wrapper);
+ rtcSetUserData(scn->rtc_scn, geom->irtc, &geom->data.mesh->filter);
+ }
+}
+
+static INLINE void
+scene_setup_embree_geometry_transform
+ (struct s3d_scene* scn, struct geometry* geom)
+{
+ ASSERT(scn && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ ASSERT(geom->type == GEOM_INSTANCE);
+ rtcSetTransform
+ (scn->rtc_scn,
+ geom->irtc,
+ RTC_MATRIX_COLUMN_MAJOR,
+ geom->data.instance->transform);
+}
+
+static INLINE res_T
+scene_setup_embree(struct s3d_scene* scn)
+{
+ struct htable_shape_iterator it, end;
+ int rtc_outdated = 0;
+ res_T res = RES_OK;
ASSERT(scn);
- ngeoms = darray_geom_size_get(&scn->embree2geoms);
- geoms = darray_geom_data_get(&scn->embree2geoms);
- FOR_EACH(i, 0, ngeoms) {
- if(!geoms[i]) continue;
+ htable_shape_begin(&scn->shapes, &it);
+ htable_shape_end(&scn->shapes, &end);
+
+ while(!htable_shape_iterator_eq(&it, &end)) {
+ struct geometry** pgeom;
+ struct geometry* geom;
+ const unsigned* shape_id = htable_shape_iterator_key_get(&it);
+ htable_shape_iterator_next(&it);
+
+ pgeom = htable_geom_find(&scn->cached_geoms, shape_id);
+ ASSERT(pgeom != NULL);
+ geom = *pgeom;
+
+ /* Define whether or not the embree scene is outdated */
+ if(geom->embree_outdated_mask) rtc_outdated = 1;
+
+ /* Register the embree geometry */
+ res = scene_register_embree_geometry(scn, geom);
+ if(res != RES_OK) goto error;
+
+ /* Flush the embree geometry states */
+ if((geom->embree_outdated_mask & EMBREE_VERTICES) != 0)
+ scene_setup_embree_geometry_positions(scn, geom);
+ if((geom->embree_outdated_mask & EMBREE_INDICES) != 0)
+ scene_setup_embree_geometry_indices(scn, geom);
+ if((geom->embree_outdated_mask & EMBREE_ENABLE) != 0)
+ scene_setup_embree_geometry_enable_state(scn, geom);
+ if((geom->embree_outdated_mask & EMBREE_FILTER_FUNCTION) != 0)
+ scene_setup_embree_geometry_filter_function(scn, geom);
+ if((geom->embree_outdated_mask & EMBREE_TRANSFORM) != 0)
+ scene_setup_embree_geometry_transform(scn, geom);
- if(geoms[i]->type == GEOM_INSTANCE)
- scene_session_clear(geoms[i]->data.instance->scene);
+ geom->embree_outdated_mask = 0;
+ }
- geometry_ref_put(geoms[i]);
+ /* Commit the embree changes */
+ if(rtc_outdated) {
+ rtcCommit(scn->rtc_scn);
}
+
+exit:
+ return res;
+error:
darray_geom_clear(&scn->embree2geoms);
+ goto exit;
+}
+
+static void
+scene_session_clear
+ (struct s3d_scene* scn,
+ const int internal) /* Is the cleared session internal? */
+{
+ ASSERT(scn && scn->session_mask != 0);
+
+ if(internal) {
+ --scn->nsessions_internal;
+ } else {
+ --scn->nsessions;
+ }
+
+ if(scn->nsessions || scn->nsessions_internal)
+ return; /* There is still an active session */
+
+ /* Recursively end the session on instantiated scene */
+ if(scn->instances_count != 0) {
+ struct htable_geom_iterator it, end;
+ size_t ninstances = 0;
+
+ htable_geom_begin(&scn->cached_geoms, &it);
+ htable_geom_end(&scn->cached_geoms, &end);
+ while(ninstances < scn->instances_count /* Early iteration stop */
+ && !htable_geom_iterator_eq(&it, &end)) {
+ struct geometry** pgeom = htable_geom_iterator_data_get(&it);
+ struct geometry* geom = *pgeom;
+ htable_geom_iterator_next(&it);
+
+ if(geom->type == GEOM_INSTANCE) {
+ scene_session_clear(geom->data.instance->scene, 1);
+ ++ninstances;
+ }
+ }
+ }
+
+ /* Clean-up session data */
+ if(scn->session_mask & S3D_TRACE)
+ darray_geom_clear(&scn->embree2geoms);
+ if(scn->session_mask & S3D_SAMPLE)
+ darray_fltui_clear(&scn->cdf);
+ if(scn->session_mask & S3D_GET_PRIMITIVE)
+ darray_nprims_cdf_clear(&scn->nprims_cdf);
+
+ /* Reset the session mask */
scn->session_mask = 0;
}
@@ -280,7 +356,6 @@ scene_register_mesh
struct geometry* geom = NULL;
size_t iattr;
unsigned shape_id;
- char upd_pos, upd_ids;
res_T res = RES_OK;
ASSERT(shape && shape->type == GEOM_MESH);
@@ -306,19 +381,15 @@ scene_register_mesh
if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
geom->irtc = RTC_INVALID_GEOMETRY_ID;
- scn->is_rtc_scn_outdated = 1;
}
mesh_clear(geom->data.mesh);
goto exit;
}
- /* Define which geometry buffers were updated */
- upd_ids = geom->data.mesh->indices != shape->data.mesh->indices;
- upd_pos = geom->data.mesh->attribs[S3D_POSITION] != shape->data.mesh->attribs[S3D_POSITION];
-
/* Get a reference onto the shape mesh indices */
if(geom->data.mesh->indices != shape->data.mesh->indices) {
- if(geom->data.mesh->indices) {
+ geom->embree_outdated_mask |= EMBREE_INDICES;
+ if(geom->data.mesh->indices) { /* Release the previous index buffer */
index_buffer_ref_put(geom->data.mesh->indices);
geom->data.mesh->indices = NULL;
}
@@ -329,10 +400,11 @@ scene_register_mesh
/* Get a reference onto the shape mesh attribs */
FOR_EACH(iattr, 0, S3D_ATTRIBS_COUNT__) {
+ geom->embree_outdated_mask |= EMBREE_VERTICES;
if(geom->data.mesh->attribs[iattr] == shape->data.mesh->attribs[iattr])
continue;
- if(geom->data.mesh->attribs[iattr]) {
+ if(geom->data.mesh->attribs[iattr]) { /* Release the previous buffer */
vertex_buffer_ref_put(geom->data.mesh->attribs[iattr]);
geom->data.mesh->attribs[iattr] = NULL;
}
@@ -344,6 +416,19 @@ scene_register_mesh
geom->data.mesh->attribs_type[iattr] = shape->data.mesh->attribs_type[iattr];
}
+ /* Update the enable flag */
+ if(geom->is_enabled != shape->is_enabled) {
+ geom->is_enabled = shape->is_enabled;
+ geom->embree_outdated_mask |= EMBREE_ENABLE;
+ }
+
+ /* Update the filter function */
+ if(geom->data.mesh->filter.func == shape->data.mesh->filter.func
+ && geom->data.mesh->filter.data == shape->data.mesh->filter.data) {
+ geom->data.mesh->filter = shape->data.mesh->filter;
+ geom->embree_outdated_mask |= EMBREE_FILTER_FUNCTION;
+ }
+
if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
struct index_buffer* shape_ids = shape->data.mesh->indices;
struct index_buffer* geom_ids = geom->data.mesh->indices;
@@ -358,23 +443,9 @@ scene_register_mesh
if(shape_nids != geom_nids || shape_nverts != geom_nverts) {
rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
geom->irtc = RTC_INVALID_GEOMETRY_ID;
- scn->is_rtc_scn_outdated = 1;
}
}
- res = scene_register_embree_geometry(scn, geom);
- if(res != RES_OK) goto error;
-
- if(upd_pos) { /* Update the Embree vertex buffer if necessary */
- scene_geometry_flush_positions(scn, geom);
- }
- if(upd_ids) { /* Update the Embree index buffer if necessary */
- scene_geometry_flush_indices(scn, geom);
- }
-
- /* Flush the remaining geometry states */
- scene_geometry_flush_enable_state(scn, geom, shape);
- scene_geometry_flush_filter_function(scn, geom, shape);
geom->flip_surface = shape->flip_surface;
exit:
@@ -395,9 +466,15 @@ scene_register_instance
res_T res = RES_OK;
ASSERT(scn && shape && shape->type == GEOM_INSTANCE);
+ /* The instance cannot contain instances, i.e. one instancing level is
+ * supported */
+ if(shape->data.instance->scene->instances_count != 0) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
/* Recursively update the scene */
- res = scene_sync(shape->data.instance->scene,
- session_mask|S3D_INSTANCE);
+ res = scene_sync(shape->data.instance->scene, session_mask, 1);
if(res != RES_OK) goto error;
S3D(shape_get_id(shape, &shape_id));
@@ -415,37 +492,17 @@ scene_register_instance
if(res != RES_OK) goto error;
geom->name = shape->id.index;
}
- /* Update the cached instance states */
ASSERT(geom->data.instance->scene == shape->data.instance->scene);
- geom->flip_surface = shape->flip_surface;
-
- /* The instance cannot contain instances, i.e. one instancing level is
- * supported */
- if(geom->data.instance->scene->instances_count != 0) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Create the Embree instance */
- res = scene_register_embree_geometry(scn, geom);
- if(res != RES_OK) goto error;
- /* Update the Embree instance transformation if necessary */
+ /* Update the Embree instance transformation if necessary */
if(!f33_eq(shape->data.instance->transform, geom->data.instance->transform)
|| !f3_eq(shape->data.instance->transform+9, geom->data.instance->transform+9)) {
-
+ geom->embree_outdated_mask |= EMBREE_TRANSFORM;
f33_set(geom->data.instance->transform, shape->data.instance->transform);
f3_set(geom->data.instance->transform+9, shape->data.instance->transform+9);
-
- rtcSetTransform
- (scn->rtc_scn,
- geom->irtc,
- RTC_MATRIX_COLUMN_MAJOR,
- geom->data.instance->transform);
- scn->is_rtc_scn_outdated = 1;
}
- scene_geometry_flush_enable_state(scn, geom, shape);
+ geom->flip_surface = shape->flip_surface;
exit:
return res;
@@ -480,7 +537,6 @@ scene_clear_cached_geometry
if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
geom->irtc = RTC_INVALID_GEOMETRY_ID;
- scn->is_rtc_scn_outdated = 1;
}
geometry_ref_put(geom);
nerased = htable_geom_erase(&scn->cached_geoms, &shape_id);
@@ -682,74 +738,82 @@ operator < (const struct nprims_cdf& it, const size_t iprim)
}
static res_T
-scene_sync(struct s3d_scene* scn, const int session_mask)
+scene_sync
+ (struct s3d_scene* scn,
+ const int session_mask,
+ const int internal) /* Is the synchronized session internal? */
{
- struct htable_shape_iterator it, end;
+ struct htable_shape_iterator it, it2, end;
res_T res = RES_OK;
ASSERT(scn);
- if((session_mask & S3D_INSTANCE) != 0
- && (scn->session_mask & S3D_INSTANCE) != 0) {
- /* The scene was already synced as an instance. Discard sync process */
- return RES_OK;
- } else if(scn->session_mask != 0) {
- /* The scene cannot be synced several times exepted if it is instantiated */
- res = RES_BAD_OP;
- goto error;
- }
-
- if((session_mask & S3D_INSTANCE) == 0 && scn->session_mask != 0) {
- res = RES_BAD_OP;
- goto error;
- }
+ /* The scene is already synced with respect to te session mask */
+ if((scn->session_mask & session_mask) == session_mask)
+ goto exit;
- htable_shape_begin(&scn->shapes, &it);
- htable_shape_end(&scn->shapes, &end);
+ if(scn->session_mask == 0) { /* Are the scene shapes already commited ? */
+ /* Commit the shape data to the back-end */
+ htable_shape_begin(&scn->shapes, &it);
+ htable_shape_end(&scn->shapes, &end);
+ while(!htable_shape_iterator_eq(&it, &end)) {
+ struct s3d_shape** pshape = htable_shape_iterator_data_get(&it);
+ struct s3d_shape* shape = *pshape;
- while(!htable_shape_iterator_eq(&it, &end)) {
- struct s3d_shape** pshape = htable_shape_iterator_data_get(&it);
- struct s3d_shape* shape = *pshape;
- htable_shape_iterator_next(&it);
+ switch(shape->type) {
+ case GEOM_INSTANCE:
+ res = scene_register_instance(scn, shape, session_mask);
+ break;
+ case GEOM_MESH:
+ res = scene_register_mesh(scn, shape);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(res != RES_OK)
+ goto error;
- switch(shape->type) {
- case GEOM_INSTANCE:
- /* One instancing level is supported */
- if((session_mask & S3D_INSTANCE) != 0) {
- res = RES_BAD_ARG;
- goto error;
- }
- res = scene_register_instance(scn, shape, session_mask);
- break;
- case GEOM_MESH:
- res = scene_register_mesh(scn, shape);
- break;
- default: FATAL("Unreachable code\n"); break;
+ htable_shape_iterator_next(&it);
}
- if(res != RES_OK)
- goto error;
+ scene_compute_aabb(scn);
}
+
+ /* Setup the scene for the S3D_TRACE session */
+ if((session_mask & S3D_TRACE) != 0) {
+ res = scene_setup_embree(scn);
+ if(res != RES_OK) goto error;
+ }
+ /* Setup the scene for the S3D_SAMPLE session */
if((session_mask & S3D_SAMPLE) != 0) {
res = scene_compute_cdf(scn);
if(res != RES_OK) goto error;
}
- if((session_mask & S3D_GET_PRIMITIVE) != 0) {
- res = scene_compute_nprims_cdf(scn, 1);
- } else {
- res = scene_compute_nprims_cdf(scn, 0);
- }
+ /* Setup the scene for the scene_primitive_id/S3D_GET_PRIMITIVE session */
+ res = scene_compute_nprims_cdf(scn, (session_mask & S3D_GET_PRIMITIVE)!=0);
if(res != RES_OK) goto error;
- if((session_mask & S3D_TRACE) != 0 && scn->is_rtc_scn_outdated) {
- rtcCommit(scn->rtc_scn);
- scn->is_rtc_scn_outdated = 0;
- }
- scn->session_mask = session_mask;
-
- scene_compute_aabb(scn);
+ scn->session_mask |= session_mask;
exit:
+ if(res == RES_OK) {
+ if(internal) {
+ ++scn->nsessions_internal;
+ } else {
+ ++scn->nsessions;
+ }
+ }
return res;
error:
+ /* Clear the session on instances that are already registered into the
+ * current session to invalidate */
+ htable_shape_begin(&scn->shapes, &it2);
+ while(!htable_shape_iterator_eq(&it2, &it)) {
+ struct s3d_shape** pshape = htable_shape_iterator_data_get(&it2);
+ struct s3d_shape* shape = *pshape;
+ htable_shape_iterator_next(&it2);
+
+ if(shape->type == GEOM_INSTANCE) {
+ scene_session_clear(shape->data.instance->scene, 1);
+ }
+ }
goto exit;
}
@@ -762,7 +826,6 @@ scene_release(ref_T* ref)
scn = CONTAINER_OF(ref, struct s3d_scene, ref);
S3D(scene_clear(scn));
dev = scn->dev;
- scene_session_clear(scn);
if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn);
htable_shape_release(&scn->shapes);
htable_geom_release(&scn->cached_geoms);
@@ -959,13 +1022,14 @@ s3d_scene_begin_session(struct s3d_scene* scn, const int session_mask)
{
if(!scn)
return RES_BAD_ARG;
+
if(!(session_mask&S3D_TRACE)
&& !(session_mask&S3D_SAMPLE)
&& !(session_mask&S3D_GET_PRIMITIVE)) {
log_error(scn->dev, "%s: no valid session is defined.\n", FUNC_NAME);
return RES_BAD_ARG;
}
- return scene_sync(scn, session_mask);
+ return scene_sync(scn, session_mask, 0/*Not an internal session*/);
}
res_T
@@ -973,26 +1037,21 @@ s3d_scene_end_session(struct s3d_scene* scn)
{
if(!scn)
return RES_BAD_ARG;
- if(scn->session_mask & S3D_INSTANCE) {
- log_error(scn->dev,
- "%s: the scene session was enabled through scene instantiation.\n",
- FUNC_NAME);
- return RES_BAD_OP;
- }
- if(!scn->session_mask) {
+
+ if(!scn->nsessions) {
log_error(scn->dev, "%s: the scene has no active session.\n", FUNC_NAME);
return RES_BAD_OP;
}
- scene_session_clear(scn);
+ ASSERT(scn->session_mask);
+ scene_session_clear(scn, 0/*Not an internal session*/);
return RES_OK;
}
res_T
s3d_scene_get_session_mask(struct s3d_scene* scn, int* session_mask)
{
- if(!scn || !session_mask)
- return RES_BAD_ARG;
- *session_mask = scn->session_mask & (~S3D_INSTANCE);
+ if(!scn || !session_mask) return RES_BAD_ARG;
+ *session_mask = scn->session_mask;
return RES_OK;
}
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -92,10 +92,11 @@ struct s3d_scene {
size_t instances_count; /* # instances in the scene */
RTCScene rtc_scn; /* Embree scene */
- char is_rtc_scn_outdated; /* Must the embree scene rebuild */
int session_mask; /* Combination of enum s3d_session_flag */
- size_t nsessions; /* # session active onto the scene */
+ size_t nsessions; /* # sessions active onto the scene */
+ /* # sessions internally enabled (i.e. through instancing) */
+ size_t nsessions_internal;
struct s3d_device* dev;
ref_T ref;
diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c
@@ -160,17 +160,18 @@ main(int argc, char** argv)
CHECK(s3d_scene_begin_session(NULL, 0), RES_BAD_ARG);
CHECK(s3d_scene_begin_session(scn, 0), RES_BAD_ARG);
CHECK(s3d_scene_begin_session(scn, S3D_TRACE|S3D_GET_PRIMITIVE), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_BAD_OP);
+ CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
CHECK(s3d_scene_get_session_mask(scn, &mask), RES_OK);
CHECK(mask & S3D_TRACE, S3D_TRACE);
- CHECK(mask & S3D_SAMPLE, 0);
+ CHECK(mask & S3D_SAMPLE, S3D_SAMPLE);
CHECK(s3d_scene_clear(scn), RES_BAD_OP);
CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_BAD_OP);
CHECK(s3d_scene_end_session(NULL), RES_BAD_ARG);
CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_end_session(scn), RES_OK);
CHECK(s3d_scene_end_session(scn), RES_BAD_OP);
CHECK(s3d_scene_get_session_mask(scn, &mask), RES_OK);
@@ -188,7 +189,7 @@ main(int argc, char** argv)
CHECK(s3d_scene_attach_shape(scn3, shapes[1]), RES_OK);
CHECK(s3d_scene_begin_session(scn2, S3D_SAMPLE|S3D_TRACE), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_BAD_OP);
+ CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
CHECK(s3d_scene_begin_session(scn3, S3D_SAMPLE), RES_OK);
CHECK(s3d_scene_end_session(scn3), RES_OK);
@@ -222,6 +223,8 @@ main(int argc, char** argv)
CHECK(lower[1] > upper[1], 1);
CHECK(lower[2] > upper[2], 1);
+ CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_end_session(scn), RES_BAD_OP);
CHECK(s3d_scene_end_session(scn2), RES_OK);
CHECK(s3d_scene_compute_area(scn2, &area), RES_BAD_OP);