commit 71014d55ed7358feeb153a39196cc5fba14abafa
parent e72f4b9c0e670b0b9e5bdae9dc11528098534245
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 26 Mar 2015 16:01:30 +0100
Ref count the internal mesh representation
Diffstat:
6 files changed, 118 insertions(+), 50 deletions(-)
diff --git a/src/s3d_instance.c b/src/s3d_instance.c
@@ -41,7 +41,7 @@
/*******************************************************************************
* Helper functions
******************************************************************************/
-void
+static void
instance_release(ref_T* ref)
{
struct instance* inst;
diff --git a/src/s3d_mesh.c b/src/s3d_mesh.c
@@ -31,6 +31,7 @@
* knowledge of the CeCILL license and that you accept its terms. */
#include "s3d_c.h"
+#include "s3d_device_c.h"
#include "s3d_mesh.h"
/*******************************************************************************
@@ -70,7 +71,7 @@ mesh_setup_indices
}
/* Allocate the new index buffer */
- res = index_buffer_create(mesh->allocator, &mesh->indices);
+ res = index_buffer_create(mesh->dev->allocator, &mesh->indices);
if(res != RES_OK) FATAL("Unsufficient memory\n");
res = darray_u32_resize(&mesh->indices->data, ntris * 3/*# triangle ids*/);
if(res != RES_OK) FATAL("Unsufficient memory\n");
@@ -123,7 +124,7 @@ mesh_setup_positions
}
/* Allocate vertex positions */
- res = vertex_buffer_create(mesh->allocator, &mesh->attribs[S3D_POSITION]);
+ res = vertex_buffer_create(mesh->dev->allocator, &mesh->attribs[S3D_POSITION]);
if(res != RES_OK) FATAL("Insufficient memory\n");
res = darray_float_resize(&mesh->attribs[S3D_POSITION]->data, nverts*3);
if(res != RES_OK) FATAL("Insufficient memory\n");
@@ -190,7 +191,7 @@ mesh_setup_attribs
}
/* Allocate the new vertex buffer */
- res = vertex_buffer_create(mesh->allocator, &mesh->attribs[attr->usage]);
+ res = vertex_buffer_create(mesh->dev->allocator, &mesh->attribs[attr->usage]);
if(res != RES_OK) FATAL("Insufficient memory\n");
res = darray_float_resize(&mesh->attribs[attr->usage]->data, nverts * dim);
if(res != RES_OK) FATAL("Insufficient memory\n");
@@ -204,16 +205,63 @@ mesh_setup_attribs
}
}
+static void
+mesh_release(ref_T* ref)
+{
+ struct mesh* mesh;
+ struct s3d_device* dev;
+ ASSERT(ref);
+
+ mesh = CONTAINER_OF(ref, struct mesh, ref);
+ mesh_clear(mesh);
+ dev = mesh->dev;
+ MEM_FREE(dev->allocator, mesh);
+ S3D(device_ref_put(dev));
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
-void
-mesh_init(struct mem_allocator* allocator, struct mesh* mesh)
+res_T
+mesh_create(struct s3d_device* dev, struct mesh** out_mesh)
{
- ASSERT(allocator && mesh);
- memset(mesh, 0, sizeof(struct mesh));
- mesh->allocator = allocator;
+ struct mesh* mesh = NULL;
+ res_T res = RES_OK;
+ ASSERT(dev && out_mesh);
+
+ mesh = (struct mesh*)MEM_CALLOC(dev->allocator, 1, sizeof(struct mesh));
+ if(!mesh) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
mesh->rtc_geom = RTC_INVALID_GEOMETRY_ID;
+ ref_init(&mesh->ref);
+ S3D(device_ref_get(dev));
+ mesh->dev = dev;
+
+exit:
+ *out_mesh = mesh;
+ return res;
+error:
+ if(!mesh) {
+ mesh_ref_put(mesh);
+ mesh = NULL;
+ }
+ goto exit;
+}
+
+void
+mesh_ref_get(struct mesh* mesh)
+{
+ ASSERT(mesh);
+ ref_get(&mesh->ref);
+}
+
+void
+mesh_ref_put(struct mesh* mesh)
+{
+ ASSERT(mesh);
+ ref_put(&mesh->ref, mesh_release);
}
void
diff --git a/src/s3d_mesh.h b/src/s3d_mesh.h
@@ -66,13 +66,22 @@ struct mesh { /* Triangular mesh */
unsigned rtc_geom; /* Embree geometry */
- struct mem_allocator* allocator;
+ struct s3d_device* dev;
+ ref_T ref;
};
+extern LOCAL_SYM res_T
+mesh_create
+ (struct s3d_device* dev,
+ struct mesh** mesh);
+
+extern LOCAL_SYM void
+mesh_ref_get
+ (struct mesh* mesh);
+
extern LOCAL_SYM void
-mesh_init
- (struct mem_allocator* allocator,
- struct mesh* mesh);
+mesh_ref_put
+ (struct mesh* mesh);
extern LOCAL_SYM void
mesh_clear
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -131,18 +131,14 @@ scene_setup_shape_mesh
if(pmesh) {
mesh = *pmesh;
} else {
- mesh = (struct mesh*)MEM_ALLOC(scn->dev->allocator, sizeof(struct mesh));
- if(!mesh) {
- res = RES_MEM_ERR;
- goto error;
- }
- mesh_init(scn->dev->allocator, mesh);
+ res = mesh_create(scn->dev, &mesh);
+ if(res != RES_OK) goto error;
res = htable_mesh_set(&scn->meshes, &shape, &mesh);
if(res != RES_OK) goto error;
}
/* Discard the shape mesh that is not geometrically valid */
- if(!shape->data.mesh.indices || !shape->data.mesh.attribs[S3D_POSITION]) {
+ 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);
mesh_clear(mesh);
@@ -150,41 +146,41 @@ scene_setup_shape_mesh
}
/* Define which Embree geometry buffer must be updated */
- upd_ids = mesh->indices != shape->data.mesh.indices
- || ((shape->data.mesh.update_mask & INDEX_BUFFER) != 0);
- upd_pos = mesh->attribs[S3D_POSITION] != shape->data.mesh.attribs[S3D_POSITION]
- || ((shape->data.mesh.update_mask == VERTEX_BUFFER) != 0);
+ upd_ids = mesh->indices != shape->data.mesh->indices
+ || ((shape->data.mesh->update_mask & INDEX_BUFFER) != 0);
+ upd_pos = mesh->attribs[S3D_POSITION] != shape->data.mesh->attribs[S3D_POSITION]
+ || ((shape->data.mesh->update_mask == VERTEX_BUFFER) != 0);
/* Get a reference onto the shape mesh indices */
- if(mesh->indices != shape->data.mesh.indices) {
+ if(mesh->indices != shape->data.mesh->indices) {
if(mesh->indices) {
index_buffer_ref_put(mesh->indices);
mesh->indices = NULL;
}
- ASSERT(shape->data.mesh.indices);
- index_buffer_ref_get(shape->data.mesh.indices);
- mesh->indices = shape->data.mesh.indices;
+ ASSERT(shape->data.mesh->indices);
+ index_buffer_ref_get(shape->data.mesh->indices);
+ mesh->indices = shape->data.mesh->indices;
}
/* Get the reference onto the shape mesh attribs */
FOR_EACH(iattr, 0, S3D_ATTRIBS_COUNT__) {
- if(mesh->attribs[iattr] == shape->data.mesh.attribs[iattr])
+ if(mesh->attribs[iattr] == shape->data.mesh->attribs[iattr])
continue;
if(mesh->attribs[iattr]) {
vertex_buffer_ref_put(mesh->attribs[iattr]);
mesh->attribs[iattr] = NULL;
}
- if(!shape->data.mesh.attribs[iattr])
+ if(!shape->data.mesh->attribs[iattr])
continue;
- vertex_buffer_ref_get(shape->data.mesh.attribs[iattr]);
- mesh->attribs[iattr] = shape->data.mesh.attribs[iattr];
- mesh->attribs_type[iattr] = shape->data.mesh.attribs_type[iattr];
+ vertex_buffer_ref_get(shape->data.mesh->attribs[iattr]);
+ mesh->attribs[iattr] = shape->data.mesh->attribs[iattr];
+ mesh->attribs_type[iattr] = shape->data.mesh->attribs_type[iattr];
}
/* 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) {
+ if(shape->data.mesh->resize_mask && mesh->rtc_geom!=RTC_INVALID_GEOMETRY_ID) {
scene_delete_mesh_rtc_geometry(scn, mesh);
}
@@ -208,8 +204,8 @@ scene_setup_shape_mesh
}
/* Flush the shape mesh states */
- shape->data.mesh.resize_mask = 0;
- shape->data.mesh.update_mask = 0;
+ shape->data.mesh->resize_mask = 0;
+ shape->data.mesh->update_mask = 0;
exit:
return res;
@@ -286,8 +282,7 @@ scene_detach_shape_mesh(struct s3d_scene* scn, struct s3d_shape* shape)
struct mesh* mesh = *pmesh;
if(mesh->rtc_geom != RTC_INVALID_GEOMETRY_ID) /* Rm the Embree geometry */
scene_delete_mesh_rtc_geometry(scn, mesh);
- mesh_clear(mesh); /* Release the mesh buffers */
- MEM_FREE(scn->dev->allocator, mesh);
+ mesh_ref_put(mesh);
htable_mesh_erase(&scn->meshes, &shape);
}
list_del(&shape->scene_attachment);
diff --git a/src/s3d_shape.c b/src/s3d_shape.c
@@ -46,11 +46,14 @@ shape_release_data(struct s3d_shape* shape)
{
ASSERT(shape);
switch(shape->type) {
- case SHAPE_MESH: mesh_clear(&shape->data.mesh); break;
+ case SHAPE_MESH:
+ if(shape->data.mesh)
+ mesh_ref_put(shape->data.mesh);
+ break;
case SHAPE_NONE: /* Do nothing */ break;
- case SHAPE_INSTANCE:
+ case SHAPE_INSTANCE:
if(shape->data.instance)
- instance_ref_put(shape->data.instance);
+ instance_ref_put(shape->data.instance);
break;
default: FATAL("Unreachable code\n"); break;
}
@@ -116,20 +119,33 @@ res_T
s3d_shape_create_mesh
(struct s3d_device* dev, struct s3d_shape** out_shape)
{
- struct s3d_shape* shape;
+ struct s3d_shape* shape = NULL;
res_T res = RES_OK;
- if(!dev || !out_shape)
- return RES_BAD_ARG;
+ if(!dev || !out_shape) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
res = shape_create(dev, &shape);
if(res != RES_OK)
- return res;
+ goto error;
+
+ res = mesh_create(dev, &shape->data.mesh);
+ if(res != RES_OK)
+ goto error;
- mesh_init(dev->allocator, &shape->data.mesh);
shape->type = SHAPE_MESH;
- *out_shape = shape;
- return RES_OK;
+exit:
+ if(out_shape)
+ *out_shape = shape;
+ return res;
+error:
+ if(shape) {
+ S3D(shape_ref_put(shape));
+ shape = NULL;
+ }
+ goto exit;
}
res_T
@@ -228,6 +244,6 @@ s3d_mesh_setup_indexed_vertices
if(!shape || shape->type != SHAPE_MESH)
return RES_BAD_ARG;
return mesh_setup_indexed_vertices
- (&shape->data.mesh, ntris, get_indices, nverts, attribs, data);
+ (shape->data.mesh, ntris, get_indices, nverts, attribs, data);
}
diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h
@@ -57,7 +57,7 @@ struct s3d_shape {
union {
struct instance* instance;
- struct mesh mesh;
+ struct mesh* mesh;
} data;
struct s3d_device* dev;