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:
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: