commit e72f4b9c0e670b0b9e5bdae9dc11528098534245
parent fdc9717a405a6ebd3fe8835fbca53f040d675743
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 26 Mar 2015 15:45:31 +0100
Ref count the internal instance representation
Diffstat:
5 files changed, 113 insertions(+), 57 deletions(-)
diff --git a/src/s3d_instance.c b/src/s3d_instance.c
@@ -32,29 +32,74 @@
#include "s3d.h"
#include "s3d_backend.h"
+#include "s3d_device_c.h"
#include "s3d_instance.h"
+#include "s3d_scene_c.h"
#include <rsys/float33.h>
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
void
-instance_init(struct instance* inst)
+instance_release(ref_T* ref)
{
- ASSERT(inst);
- inst->scene = NULL;
+ struct instance* inst;
+ struct s3d_scene* scn;
+ ASSERT(ref);
+ inst = CONTAINER_OF(ref, struct instance, ref);
+ scn = inst->scene;
+ MEM_FREE(scn->dev->allocator, inst);
+ S3D(scene_ref_put(scn));
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+instance_create
+ (struct s3d_scene* scn,
+ struct instance** out_inst)
+{
+ struct instance* inst = NULL;
+ res_T res = RES_OK;
+ ASSERT(scn && out_inst);
+
+ inst = (struct instance*)
+ MEM_CALLOC(scn->dev->allocator, 1, sizeof(struct instance));
+ if(!inst) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
f33_set_identity(inst->transform); /* rotation */
f3_splat(inst->transform + 9, 0.f); /* Translation */
inst->update_transform = 0;
inst->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+ ref_init(&inst->ref);
+ S3D(scene_ref_get(scn));
+ inst->scene = scn;
+exit:
+ *out_inst = inst;
+ return res;
+error:
+ if(inst) {
+ instance_ref_put(inst);
+ inst = NULL;
+ }
+ goto exit;
}
void
-instance_clear(struct instance* inst)
+instance_ref_get(struct instance* inst)
{
ASSERT(inst);
- if(inst->scene) {
- S3D(scene_ref_put(inst->scene));
- inst->scene = NULL;
- }
+ ref_get(&inst->ref);
}
+void
+instance_ref_put(struct instance* inst)
+{
+ ASSERT(inst);
+ ref_put(&inst->ref, instance_release);
+}
diff --git a/src/s3d_instance.h b/src/s3d_instance.h
@@ -33,19 +33,28 @@
#ifndef S3D_INSTANCE_H
#define S3D_INSTANCE_H
+#include <rsys/ref_count.h>
+
struct instance {
- struct s3d_scene* scene;
float transform[12]; /* local to world 3x4 column major matrix */
char update_transform;
unsigned rtc_geom;
+
+ struct s3d_scene* scene;
+ ref_T ref;
};
+extern LOCAL_SYM res_T
+instance_create
+ (struct s3d_scene* scene,
+ struct instance** inst);
+
extern LOCAL_SYM void
-instance_init
+instance_ref_get
(struct instance* inst);
extern LOCAL_SYM void
-instance_clear
+instance_ref_put
(struct instance* inst);
#endif /* S3D_INSTANCE_H */
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -226,7 +226,7 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
ASSERT(scn && shape && shape->type == SHAPE_INSTANCE);
/* Recursuvely update the scene */
- res = s3d_scene_build(shape->data.instance.scene);
+ res = s3d_scene_build(shape->data.instance->scene);
if(res != RES_OK) goto error;
pinst = htable_inst_find(&scn->instances, &shape);
@@ -234,25 +234,15 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
if(pinst) {
inst = *pinst;
} else {
- inst = (struct instance*)
- MEM_ALLOC(scn->dev->allocator, sizeof(struct instance));
- if(!inst) {
- res = RES_MEM_ERR;
- goto error;
- }
- instance_init(inst);
+ res = instance_create(shape->data.instance->scene, &inst);
+ if(res != RES_OK) goto error;
res = htable_inst_set(&scn->instances, &shape, &inst);
if(res != RES_OK) goto error;
- /* It is not necessary to get a reference onto the instantiated scene since
- * the scene get a reference onto its shape. Anyway it is actually more
- * consistent */
- S3D(scene_ref_get(shape->data.instance.scene));
- inst->scene = shape->data.instance.scene;
}
- ASSERT(inst->scene == shape->data.instance.scene);
- f33_set(inst->transform, shape->data.instance.transform);
- f3_set(inst->transform + 9, shape->data.instance.transform + 9);
+ ASSERT(inst->scene == shape->data.instance->scene);
+ f33_set(inst->transform, shape->data.instance->transform);
+ f3_set(inst->transform + 9, shape->data.instance->transform + 9);
/* The instance cannot contain instances */
if(darray_geom2inst_size_get(&inst->scene->geom2inst)) {
@@ -267,7 +257,7 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
}
/* Update the Embree instance transformation */
- if(shape->data.instance.update_transform) {
+ if(shape->data.instance->update_transform) {
rtcSetTransform
(scn->rtc_scn,
inst->rtc_geom,
@@ -276,7 +266,7 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
scn->is_rtc_scn_outdated = 1;
}
- shape->data.instance.update_transform = 0; /* Flush instance state */
+ shape->data.instance->update_transform = 0; /* Flush instance state */
exit:
return res;
@@ -316,8 +306,7 @@ scene_detach_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
struct instance* inst = *pinst;
if(inst->rtc_geom != RTC_INVALID_GEOMETRY_ID)
scene_delete_instance_rtc_geometry(scn, inst);
- instance_clear(inst);
- MEM_FREE(scn->dev->allocator, inst);
+ instance_ref_put(inst);
htable_inst_erase(&scn->instances, &shape);
}
list_del(&shape->scene_attachment);
@@ -420,22 +409,32 @@ s3d_scene_ref_put(struct s3d_scene* scn)
res_T
s3d_scene_instantiate(struct s3d_scene* scn, struct s3d_shape** out_shape)
{
- struct s3d_shape* shape;
+ struct s3d_shape* shape = NULL;
res_T res = RES_OK;
- if(!scn || !out_shape)
- return RES_BAD_ARG;
-
+ if(!scn || !out_shape) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
res = shape_create(scn->dev, &shape);
if(res != RES_OK)
- return res;
+ goto error;
shape->type = SHAPE_INSTANCE;
- instance_init(&shape->data.instance);
- S3D(scene_ref_get(scn));
- shape->data.instance.scene = scn;
- *out_shape = shape;
- return RES_OK;
+ res = instance_create(scn, &shape->data.instance);
+ if(res != RES_OK)
+ goto error;
+
+exit:
+ if(out_shape)
+ *out_shape = shape;
+ return res;
+error:
+ if(shape) {
+ S3D(shape_ref_put(shape));
+ shape = NULL;
+ }
+ goto exit;
}
res_T
diff --git a/src/s3d_shape.c b/src/s3d_shape.c
@@ -48,7 +48,10 @@ shape_release_data(struct s3d_shape* shape)
switch(shape->type) {
case SHAPE_MESH: mesh_clear(&shape->data.mesh); break;
case SHAPE_NONE: /* Do nothing */ break;
- case SHAPE_INSTANCE: instance_clear(&shape->data.instance); break;
+ case SHAPE_INSTANCE:
+ if(shape->data.instance)
+ instance_ref_put(shape->data.instance);
+ break;
default: FATAL("Unreachable code\n"); break;
}
shape->type = SHAPE_NONE;
@@ -175,13 +178,13 @@ s3d_instance_set_position
float axis[3];
if(!shape || shape->type != SHAPE_INSTANCE || !position)
return RES_BAD_ARG;
- shape->data.instance.transform[9] =
- f3_dot(f33_row(axis, shape->data.instance.transform, 0), position);
- shape->data.instance.transform[10] =
- f3_dot(f33_row(axis, shape->data.instance.transform, 1), position);
- shape->data.instance.transform[11] =
- f3_dot(f33_row(axis, shape->data.instance.transform, 2), position);
- shape->data.instance.update_transform = 1;
+ shape->data.instance->transform[9] =
+ f3_dot(f33_row(axis, shape->data.instance->transform, 0), position);
+ shape->data.instance->transform[10] =
+ f3_dot(f33_row(axis, shape->data.instance->transform, 1), position);
+ shape->data.instance->transform[11] =
+ f3_dot(f33_row(axis, shape->data.instance->transform, 2), position);
+ shape->data.instance->update_transform = 1;
return RES_OK;
}
@@ -195,18 +198,18 @@ s3d_instance_translate
return RES_BAD_ARG;
if(space == S3D_LOCAL_TRANSFORM) {
float vec[3];
- f33_mulf3(vec, shape->data.instance.transform, translation);
+ f33_mulf3(vec, shape->data.instance->transform, translation);
f3_add
- (shape->data.instance.transform + 9,
- shape->data.instance.transform + 9,
+ (shape->data.instance->transform + 9,
+ shape->data.instance->transform + 9,
vec);
- shape->data.instance.update_transform = 1;
+ shape->data.instance->update_transform = 1;
} else if(space == S3D_WORLD_TRANSFORM) {
f3_add
- (shape->data.instance.transform + 9,
- shape->data.instance.transform + 9,
+ (shape->data.instance->transform + 9,
+ shape->data.instance->transform + 9,
translation);
- shape->data.instance.update_transform = 1;
+ shape->data.instance->update_transform = 1;
} else {
return RES_BAD_ARG;
}
diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h
@@ -56,7 +56,7 @@ struct s3d_shape {
enum shape_type type;
union {
- struct instance instance;
+ struct instance* instance;
struct mesh mesh;
} data;