star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.fr/star-3d.git
Log | Files | Refs | README | LICENSE

commit 9dae4823d07e3b0435001a0e53b370ac54303a85
parent ff819559a704106ada6e09ffe54ff24cf45f53da
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 18 Mar 2015 14:51:45 +0100

Major update and fix of the API threading model

Diffstat:
Msrc/s3d_scene.c | 78++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/s3d_scene_c.h | 9+--------
Msrc/s3d_shape.c | 16++--------------
3 files changed, 37 insertions(+), 66 deletions(-)

diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -68,7 +68,8 @@ scene_setup(struct s3d_scene* scn) const size_t ntris = darray_u32_size_get(&shape->data.mesh.indices)/3; const size_t nverts = darray_float_size_get (&shape->data.mesh.attribs[S3D_POSITION])/3; - /*ASSERT(IS_ALIGNED(ids, 16));*/ + + mutex_rw_rlock(shape->lock); /* Prevent concurrent shape update */ /* The Embree geometry is no more valid */ if(shape->data.mesh.resize_mask @@ -96,10 +97,14 @@ scene_setup(struct s3d_scene* scn) if(shape->rtc_geom >= darray_geom2shape_size_get(&scn->geom2shape)) { res = darray_geom2shape_resize(&scn->geom2shape, shape->rtc_geom+1); - if(res != RES_OK) goto error; + if(res != RES_OK) { + mutex_rw_unlock(shape->lock); + goto error; + } } darray_geom2shape_data_get(&scn->geom2shape)[shape->rtc_geom] = shape; } + mutex_rw_unlock(shape->lock); } exit: @@ -118,8 +123,8 @@ error: static INLINE void scene_remove_shape_unsafe(struct s3d_scene* scn, struct s3d_shape* shape) { - ASSERT(shape->scn == scn); mutex_rw_wlock(shape->lock); + ASSERT(shape->scn == scn); if(is_list_empty(&shape->scene_attachment)) /* No more attached */ return; if(shape->rtc_geom != RTC_INVALID_GEOMETRY_ID) @@ -139,10 +144,9 @@ scene_release(ref_T* ref) scn = CONTAINER_OF(ref, struct s3d_scene, ref); S3D(scene_clear(scn)); dev = scn->dev; - if(scn->rtc_scn) - rtcDeleteScene(scn->rtc_scn); - if(scn->lock) - mutex_destroy(scn->lock); + if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn); + if(scn->lock) mutex_destroy(scn->lock); + if(scn->lock_rtc) mutex_rw_destroy(scn->lock_rtc); darray_geom2shape_release(&scn->geom2shape); MEM_FREE(dev->allocator, scn); S3D(device_ref_put(dev)); @@ -173,7 +177,6 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) S3D(device_ref_get(dev)); scn->dev = dev; scn->is_outdated = 0; - scn->status = SCENE_READY; scn->rtc_scn = rtcNewScene (RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT, RTC_INTERSECT1 | RTC_INTERSECT4); @@ -186,6 +189,11 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) res = RES_MEM_ERR; goto error; } + scn->lock_rtc = mutex_rw_create(); + if(!scn->lock_rtc) { + res = RES_MEM_ERR; + goto error; + } /* Commit empty scene => the scene can be ray traced whithout any pull */ rtcCommit(scn->rtc_scn); @@ -270,37 +278,27 @@ res_T s3d_scene_pull(struct s3d_scene* scn) { res_T res = RES_OK; - enum scene_status status; if(!scn) return RES_BAD_ARG; - status = ATOMIC_CAS(&scn->status, SCENE_PULL, SCENE_READY); - if(status == SCENE_RAY_TRACE || status == SCENE_COMMIT) { - /* The scene cannot be pulled while it is ray traced or updated */ - res = RES_BAD_ARG; /* TODO return a RES_BAD_OP instead */ - goto error; - } else { - /* Prevent the scene_<attach/remove_shape|clear|pull> operations */ - mutex_lock(scn->lock); - if(scn->is_outdated) { - res = scene_setup(scn); - rtcCommit(scn->rtc_scn); - scn->is_outdated = res != RES_OK; - } - mutex_unlock(scn->lock); + /* Prevent the scene_<attach/remove_shape|clear|pull> operations */ + mutex_lock(scn->lock); + /* Prevent concurrent ray tracing */ + mutex_rw_wlock(scn->lock_rtc); - /* The status is necessaraly SCENE_PULL */ - ASSERT(scn->status == SCENE_PULL); - ATOMIC_SET(&scn->status, SCENE_READY); - if(res != RES_OK) - goto error; + if(scn->is_outdated) { + res = scene_setup(scn); + rtcCommit(scn->rtc_scn); + scn->is_outdated = res != RES_OK; } + mutex_unlock(scn->lock); + mutex_rw_unlock(scn->lock_rtc); -exit: - return res; -error: - goto exit; + if(res != RES_OK) + return res; + + return RES_OK; } res_T @@ -318,11 +316,6 @@ s3d_scene_trace_ray if(!f3_is_normalized(dir) || range[0] < 0.f || range[0] > range[1]) return RES_BAD_ARG; - if(ATOMIC_CAS(&scn->status, SCENE_RAY_TRACE, SCENE_READY) == SCENE_PULL) { - /* A scene cannot be ray-traced while it is pulled */ - return RES_BAD_ARG; /* TODO return a RES_BAD_OP instead */ - } - f3_set(ray.org, org); f3_set(ray.dir, dir); ray.tnear = range[0]; @@ -333,8 +326,10 @@ s3d_scene_trace_ray ray.mask = 0xFFFFFFFF; ray.time = 0.f; + /* Prevent concurrent modifications on the Embree scene */ + mutex_rw_rlock(scn->lock_rtc); rtcIntersect(scn->rtc_scn, ray); - ATOMIC_CAS(&scn->status, SCENE_READY, SCENE_RAY_TRACE); + mutex_rw_unlock(scn->lock_rtc); if(ray.geomID == RTC_INVALID_GEOMETRY_ID) { *hit = S3D_HIT_NULL; @@ -348,12 +343,7 @@ s3d_scene_trace_ray hit->shape = darray_geom2shape_data_get(&scn->geom2shape)[ray.geomID]; ASSERT(hit->shape != NULL && ray.geomID == hit->shape->rtc_geom); } - - -exit: - return res; -error: - goto exit; + return RES_OK; } /******************************************************************************* diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -43,21 +43,14 @@ #define DARRAY_DATA struct s3d_shape* #include <rsys/dynamic_array.h> -enum scene_status { - SCENE_PULL, /* The scene is pulling its updates */ - SCENE_COMMIT, /* Some scene shapes are updating */ - SCENE_RAY_TRACE, /* The scene is ray-traced */ - SCENE_READY /* The scene can accept any operation */ -}; - struct s3d_scene { struct list_node shapes; /* List of attached shapes */ struct darray_geom2shape geom2shape; RTCScene rtc_scn; char is_outdated; /* Flag defining if the scene description was updated */ - enum scene_status status; struct mutex* lock; + struct mutex_rw* lock_rtc; struct s3d_device* dev; ref_T ref; diff --git a/src/s3d_shape.c b/src/s3d_shape.c @@ -349,7 +349,7 @@ s3d_shape_detach(struct s3d_shape* shape) { char is_attached; if(!shape) return RES_BAD_ARG; - if(S3D(shape_is_attached(shape, &is_attached)), !is_attached) + if(!(S3D(shape_is_attached(shape, &is_attached)), is_attached)) return RES_OK; scene_remove_shape(shape->scn, shape); return RES_OK; @@ -375,19 +375,9 @@ s3d_shape_mesh_setup_indexed_vertices if(!shape || shape->type != SHAPE_MESH || !ntris || !nverts || !attribs) return RES_BAD_ARG; - /* Prevent the shape from its concurrent attachment/detachment & update */ + /* Prevent the shape from its concurrent attachment/detachment & pull */ mutex_rw_wlock(shape->lock); - if(!is_list_empty(&shape->scene_attachment)) { - if(ATOMIC_CAS(&shape->scn->status, SCENE_COMMIT, SCENE_READY)==SCENE_PULL) { - /* Is there any use case where a scene is pulling shapes while its - * associated data were updated ? Currently it seems that it reveals only - * an unexpected comportment */ - res = RES_BAD_ARG; /* FIXME return a RES_BAD_OP instead */ - goto error; - } - } - /* Check indices description */ if(get_indices == S3D_KEEP) { const unsigned nids_prev = darray_u32_size_get(&shape->data.mesh.indices); @@ -441,8 +431,6 @@ s3d_shape_mesh_setup_indexed_vertices shape->scn->is_outdated = 1; exit: - if(!is_list_empty(&shape->scene_attachment)) /* Restore scene status */ - ATOMIC_CAS(&shape->scn->status, SCENE_READY, SCENE_COMMIT); mutex_rw_unlock(shape->lock); return res; error: