commit 547e4c9d03d7b1bccb72672b112e108bad13466f
parent 71014d55ed7358feeb153a39196cc5fba14abafa
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 27 Mar 2015 09:20:56 +0100
Make robust a scene build to the shape removal/scene clear operations
Diffstat:
6 files changed, 126 insertions(+), 55 deletions(-)
diff --git a/src/s3d.h b/src/s3d.h
@@ -132,6 +132,7 @@ static const struct s3d_hit S3D_HIT_NULL =
/* Forward declaration of s3d opaque data types */
struct s3d_device; /* Entry point of the library */
+struct s3d_rt_session; /* Ray tracing session */
struct s3d_scene; /* Collection of shapes */
struct s3d_shape; /* Untyped geometry */
@@ -317,6 +318,22 @@ s3d_instance_translate
const enum s3d_transform_space space,
const float translation[3]);
+/*******************************************************************************
+ * RT Session
+ ******************************************************************************/
+S3D_API res_T
+s3d_rt_session_create
+ (struct s3d_scene* scn,
+ struct s3d_rt_session** session);
+
+S3D_API res_T
+s3d_rt_session_ref_get
+ (struct s3d_rt_session* session);
+
+S3D_API res_T
+s3d_rt_session_ref_put
+ (struct s3d_rt_session* session);
+
END_DECLS
#endif /* S3D_H */
diff --git a/src/s3d_instance.c b/src/s3d_instance.c
@@ -49,6 +49,8 @@ instance_release(ref_T* ref)
ASSERT(ref);
inst = CONTAINER_OF(ref, struct instance, ref);
scn = inst->scene;
+ if(inst->rtc_geom != RTC_INVALID_GEOMETRY_ID)
+ instance_delete_rtc_geom(inst);
MEM_FREE(scn->dev->allocator, inst);
S3D(scene_ref_put(scn));
}
@@ -103,3 +105,19 @@ instance_ref_put(struct instance* inst)
ref_put(&inst->ref, instance_release);
}
+void
+instance_create_rtc_geom(struct instance* inst, RTCScene scn)
+{
+ ASSERT(inst && inst->rtc_geom == RTC_INVALID_GEOMETRY_ID && scn);
+ inst->rtc_geom = rtcNewInstance(scn, inst->scene->rtc_scn);
+ inst->rtc_scn = scn;
+}
+
+void
+instance_delete_rtc_geom(struct instance* inst)
+{
+ ASSERT(inst && inst->rtc_geom != RTC_INVALID_GEOMETRY_ID && inst->rtc_scn);
+ rtcDeleteGeometry(inst->rtc_scn, inst->rtc_geom);
+ inst->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+ inst->rtc_scn = NULL;
+}
diff --git a/src/s3d_instance.h b/src/s3d_instance.h
@@ -38,6 +38,8 @@
struct instance {
float transform[12]; /* local to world 3x4 column major matrix */
char update_transform;
+
+ RTCScene rtc_scn;
unsigned rtc_geom;
struct s3d_scene* scene;
@@ -57,5 +59,14 @@ extern LOCAL_SYM void
instance_ref_put
(struct instance* inst);
+extern LOCAL_SYM void
+instance_create_rtc_geom
+ (struct instance* inst,
+ RTCScene rtc_scn);
+
+extern LOCAL_SYM void
+instance_delete_rtc_geom
+ (struct instance* inst);
+
#endif /* S3D_INSTANCE_H */
diff --git a/src/s3d_mesh.c b/src/s3d_mesh.c
@@ -215,6 +215,8 @@ mesh_release(ref_T* ref)
mesh = CONTAINER_OF(ref, struct mesh, ref);
mesh_clear(mesh);
dev = mesh->dev;
+ if(mesh->rtc_geom != RTC_INVALID_GEOMETRY_ID)
+ mesh_delete_rtc_geom(mesh);
MEM_FREE(dev->allocator, mesh);
S3D(device_ref_put(dev));
}
@@ -235,6 +237,7 @@ mesh_create(struct s3d_device* dev, struct mesh** out_mesh)
goto error;
}
mesh->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+ mesh->rtc_scn = NULL;
ref_init(&mesh->ref);
S3D(device_ref_get(dev));
mesh->dev = dev;
@@ -265,6 +268,24 @@ mesh_ref_put(struct mesh* mesh)
}
void
+mesh_create_rtc_geom(struct mesh* mesh, RTCScene scn)
+{
+ ASSERT(mesh && mesh->rtc_geom == RTC_INVALID_GEOMETRY_ID && scn);
+ mesh->rtc_geom = rtcNewTriangleMesh(scn, RTC_GEOMETRY_DYNAMIC,
+ mesh_get_ntris(mesh), mesh_get_nverts(mesh));
+ mesh->rtc_scn = scn;
+}
+
+void
+mesh_delete_rtc_geom(struct mesh* mesh)
+{
+ ASSERT(mesh && mesh->rtc_geom != RTC_INVALID_GEOMETRY_ID && mesh->rtc_scn);
+ rtcDeleteGeometry(mesh->rtc_scn, mesh->rtc_geom);
+ mesh->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+ mesh->rtc_scn = NULL;
+}
+
+void
mesh_clear(struct mesh* mesh)
{
size_t iattr;
diff --git a/src/s3d_mesh.h b/src/s3d_mesh.h
@@ -64,6 +64,7 @@ struct mesh { /* Triangular mesh */
int resize_mask; /* Combination of buffer_type */
int update_mask; /* Combination of buffer_type */
+ RTCScene rtc_scn; /* Embree scene from which rtc_geom was created */
unsigned rtc_geom; /* Embree geometry */
struct s3d_device* dev;
@@ -84,6 +85,15 @@ mesh_ref_put
(struct mesh* mesh);
extern LOCAL_SYM void
+mesh_create_rtc_geom
+ (struct mesh* mesh,
+ RTCScene rtc_scn);
+
+extern LOCAL_SYM void
+mesh_delete_rtc_geom
+ (struct mesh* mesh);
+
+extern LOCAL_SYM void
mesh_clear
(struct mesh* mesh);
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -44,73 +44,73 @@
* Helper functions
******************************************************************************/
static res_T
-scene_create_mesh_rtc_geometry(struct s3d_scene* scn, struct mesh* mesh)
+scene_build_register_mesh(struct s3d_scene* scn, struct mesh* mesh)
{
- ASSERT(scn && mesh && mesh->rtc_geom == RTC_INVALID_GEOMETRY_ID);
- mesh->rtc_geom = rtcNewTriangleMesh(scn->rtc_scn, RTC_GEOMETRY_DYNAMIC,
- mesh_get_ntris(mesh), mesh_get_nverts(mesh));
+ ASSERT(scn && mesh);
+ /* Create the Embree geometry if it is not valid */
+ if(mesh->rtc_geom == RTC_INVALID_GEOMETRY_ID) {
+ mesh_create_rtc_geom(mesh, scn->rtc_scn);
+ scn->is_rtc_scn_outdated = 1;
+ }
- /* Map the Embree geometry to its scene mesh */
if(mesh->rtc_geom >= darray_geom2mesh_size_get(&scn->geom2mesh)) {
res_T res = darray_geom2mesh_resize(&scn->geom2mesh, mesh->rtc_geom + 1);
if(res != RES_OK) {
rtcDeleteGeometry(scn->rtc_scn, mesh->rtc_geom);
mesh->rtc_geom = RTC_INVALID_GEOMETRY_ID;
return res;
- } else {
- /* Check that no other mesh is mapped to this Embree geometry */
- ASSERT(!darray_geom2mesh_data_get(&scn->geom2mesh)[mesh->rtc_geom]);
}
+ mesh_ref_get(mesh);
darray_geom2mesh_data_get(&scn->geom2mesh)[mesh->rtc_geom] = mesh;
- scn->is_rtc_scn_outdated = 1;
}
return RES_OK;
}
-static void
-scene_delete_mesh_rtc_geometry(struct s3d_scene* scn, struct mesh* mesh)
-{
- ASSERT(scn && mesh && mesh->rtc_geom != RTC_INVALID_GEOMETRY_ID);
- ASSERT(darray_geom2mesh_size_get(&scn->geom2mesh) > mesh->rtc_geom);
- darray_geom2mesh_data_get(&scn->geom2mesh)[mesh->rtc_geom] = NULL;
- rtcDeleteGeometry(scn->rtc_scn, mesh->rtc_geom);
- mesh->rtc_geom = RTC_INVALID_GEOMETRY_ID;
- scn->is_rtc_scn_outdated = 1;
-}
-
static res_T
-scene_create_instance_rtc_geometry(struct s3d_scene* scn, struct instance* inst)
+scene_build_register_instance(struct s3d_scene* scn, struct instance* inst)
{
- ASSERT(scn && inst && inst->scene && inst->rtc_geom == RTC_INVALID_GEOMETRY_ID);
+ ASSERT(scn && inst && inst->scene);
/* The instance should not contain instances */
ASSERT(!darray_geom2inst_size_get(&inst->scene->geom2inst));
- inst->rtc_geom = rtcNewInstance(scn->rtc_scn, inst->scene->rtc_scn);
+ if(inst->rtc_geom) {
+ instance_create_rtc_geom(inst, scn->rtc_scn);
+ scn->is_rtc_scn_outdated = 1;
+ }
+
if(inst->rtc_geom >= darray_geom2inst_size_get(&scn->geom2inst)) {
res_T res = darray_geom2inst_resize(&scn->geom2inst, inst->rtc_geom + 1);
if(res != RES_OK) {
rtcDeleteGeometry(scn->rtc_scn, inst->rtc_geom);
inst->rtc_geom = RTC_INVALID_GEOMETRY_ID;
return res;
- } else {
- /* Check that no other scene is mapped to this Embree geometry */
- ASSERT(!darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom]);
}
+ instance_ref_get(inst);
darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom] = inst;
- scn->is_rtc_scn_outdated = 1;
}
return RES_OK;
}
static void
-scene_delete_instance_rtc_geometry(struct s3d_scene* scn, struct instance* inst)
+scene_build_clear(struct s3d_scene* scn)
{
- ASSERT(scn && inst && inst->rtc_geom != RTC_INVALID_GEOMETRY_ID);
- ASSERT(darray_geom2inst_size_get(&scn->geom2inst) > inst->rtc_geom);
- darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom] = NULL;
- rtcDeleteGeometry(scn->rtc_scn, inst->rtc_geom);
- inst->rtc_geom = RTC_INVALID_GEOMETRY_ID;
- scn->is_rtc_scn_outdated = 1;
+ struct mesh** meshes;
+ struct instance** instances;
+ size_t nmeshes;
+ size_t ninstances;
+ size_t i;
+ ASSERT(scn);
+
+ nmeshes = darray_geom2mesh_size_get(&scn->geom2mesh);
+ meshes = darray_geom2mesh_data_get(&scn->geom2mesh);
+ FOR_EACH(i, 0, nmeshes) if(meshes[i]) mesh_ref_put(meshes[i]);
+ darray_geom2mesh_clear(&scn->geom2mesh);
+
+ ninstances = darray_geom2inst_size_get(&scn->geom2inst);
+ instances = darray_geom2inst_data_get(&scn->geom2inst);
+ FOR_EACH(i, 0, ninstances) if(instances[i]) instance_ref_put(instances[i]);
+ darray_geom2inst_clear(&scn->geom2inst);
+ scn->is_rtc_scn_outdated = 0;
}
static res_T
@@ -139,8 +139,10 @@ scene_setup_shape_mesh
/* Discard the shape mesh that is not geometrically valid */
if(!shape->data.mesh->indices || !shape->data.mesh->attribs[S3D_POSITION]) {
- if(mesh->rtc_geom != RTC_INVALID_GEOMETRY_ID)
- scene_delete_mesh_rtc_geometry(scn, mesh);
+ if(mesh->rtc_geom != RTC_INVALID_GEOMETRY_ID) {
+ mesh_delete_rtc_geom(mesh);
+ scn->is_rtc_scn_outdated = 1;
+ }
mesh_clear(mesh);
goto exit;
}
@@ -181,14 +183,12 @@ scene_setup_shape_mesh
/* The shape mesh was resize => the Embree geometry is no more valid */
if(shape->data.mesh->resize_mask && mesh->rtc_geom!=RTC_INVALID_GEOMETRY_ID) {
- scene_delete_mesh_rtc_geometry(scn, mesh);
+ mesh_delete_rtc_geom(mesh);
+ scn->is_rtc_scn_outdated = 1;
}
- /* Create the Embree geometry of the scene mesh */
- if(mesh->rtc_geom == RTC_INVALID_GEOMETRY_ID) {
- res = scene_create_mesh_rtc_geometry(scn, mesh);
- if(res != RES_OK) goto error;
- }
+ res = scene_build_register_mesh(scn, mesh);
+ if(res != RES_OK) goto error;
if(upd_pos) { /* Update the Embree vertex buffer if necessary */
rtcSetBuffer(scn->rtc_scn, mesh->rtc_geom, RTC_VERTEX_BUFFER,
@@ -247,10 +247,8 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
}
/* Create the Embree instance */
- if(inst->rtc_geom == RTC_INVALID_GEOMETRY_ID) {
- res = scene_create_instance_rtc_geometry(scn, inst);
- if(res != RES_OK) goto error;
- }
+ res = scene_build_register_instance(scn, inst);
+ if(res != RES_OK) goto error;
/* Update the Embree instance transformation */
if(shape->data.instance->update_transform) {
@@ -278,10 +276,8 @@ scene_detach_shape_mesh(struct s3d_scene* scn, struct s3d_shape* shape)
ASSERT(shape->type == SHAPE_MESH);
pmesh = htable_mesh_find(&scn->meshes, &shape);
- if(pmesh) { /* The shape mesh is registered into the scene */
+ if(pmesh) { /* The shape mesh is cached into the scene */
struct mesh* mesh = *pmesh;
- if(mesh->rtc_geom != RTC_INVALID_GEOMETRY_ID) /* Rm the Embree geometry */
- scene_delete_mesh_rtc_geometry(scn, mesh);
mesh_ref_put(mesh);
htable_mesh_erase(&scn->meshes, &shape);
}
@@ -297,10 +293,8 @@ scene_detach_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
ASSERT(shape->type == SHAPE_INSTANCE);
pinst = htable_inst_find(&scn->instances, &shape);
- if(pinst) { /* The shape instance is registered into the scene */
+ if(pinst) { /* The shape instance is cached into the scene */
struct instance* inst = *pinst;
- if(inst->rtc_geom != RTC_INVALID_GEOMETRY_ID)
- scene_delete_instance_rtc_geometry(scn, inst);
instance_ref_put(inst);
htable_inst_erase(&scn->instances, &shape);
}
@@ -328,6 +322,7 @@ scene_release(ref_T* ref)
scn = CONTAINER_OF(ref, struct s3d_scene, ref);
S3D(scene_clear(scn));
dev = scn->dev;
+ scene_build_clear(scn);
if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn);
htable_mesh_release(&scn->meshes);
htable_inst_release(&scn->instances);
@@ -493,6 +488,7 @@ s3d_scene_build(struct s3d_scene* scn)
goto error;
}
+ scene_build_clear(scn);
LIST_FOR_EACH(node, &scn->shapes) {
struct s3d_shape* shape = CONTAINER_OF
(node, struct s3d_shape, scene_attachment);
@@ -504,10 +500,8 @@ s3d_scene_build(struct s3d_scene* scn)
if(res != RES_OK)
goto error;
}
- if(scn->is_rtc_scn_outdated) {
+ if(scn->is_rtc_scn_outdated)
rtcCommit(scn->rtc_scn);
- scn->is_rtc_scn_outdated = 0;
- }
exit:
return res;