commit c46c63425cf1be297a5d333c3ad0258e660bfefb
parent 16a6c702b23d0f0154e9584813315826d288a493
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 8 Sep 2022 11:54:13 +0200
Add support for octree loading
Diffstat:
6 files changed, 171 insertions(+), 27 deletions(-)
diff --git a/src/rnatm.c b/src/rnatm.c
@@ -91,6 +91,10 @@ check_rnatm_create_args(const struct rnatm_create_args* args)
if(args->spectral_range[0] > args->spectral_range[1])
return RES_BAD_ARG;
+ /* Invalid requirements for loading octrees */
+ if(!args->octrees_storage && args->load_octrees_from_storage)
+ return RES_BAD_ARG;
+
/* Check miscalleneous arguments */
if(!args->name
|| args->optical_thickness < 0
@@ -134,7 +138,6 @@ create_rnatm
ref_init(&atm->ref);
atm->allocator = allocator;
atm->verbose = args->verbose;
- atm->octrees_storage = args->octrees_storage;
str_init(atm->allocator, &atm->name);
gas_init(atm->allocator, &atm->gas);
darray_aerosol_init(atm->allocator, &atm->aerosols);
diff --git a/src/rnatm.h b/src/rnatm.h
@@ -86,9 +86,14 @@ struct rnatm_create_args {
char* name; /* Name of the atmosphere */
/* Read/write file where octrees are offloaded. May be NULL => octrees are
- * kept in memory */
+ * built at runtime and kept in memory */
FILE* octrees_storage;
+ /* Defines whether the octrees to be taken into account have already been
+ * unloaded into 'octrees_storage' at a previous run and, therefore, can be
+ * loaded from the provided file rather than built from scratch */
+ int load_octrees_from_storage;
+
/* Spectral range to consider (in nanometers). Limits are inclusive */
double spectral_range[2];
double optical_thickness; /* Threshold used during octree building */
@@ -109,6 +114,7 @@ struct rnatm_create_args {
"atmosphere", /* Name */ \
\
NULL, /* octrees storage */ \
+ 0, \
\
{380, 780}, /* Spectral range */ \
1, /* Optical thickness */ \
diff --git a/src/rnatm_octree.c b/src/rnatm_octree.c
@@ -1157,6 +1157,47 @@ vx_challenge_merge
}
static res_T
+init_octrees_storage(struct rnatm* atm, const struct rnatm_create_args* args)
+{
+ struct octrees_storage_desc desc;
+ res_T res = RES_OK;
+ ASSERT(atm && args);
+
+ if(!args->octrees_storage) goto exit;
+
+ /* Register the storage file */
+ atm->octrees_storage = args->octrees_storage;
+
+ res = setup_octrees_storage_desc(atm, &desc);
+ if(res != RES_OK) goto error;
+
+ /* Save the computed descriptor in the storage */
+ if(!args->load_octrees_from_storage) {
+ res = write_octrees_storage_desc(atm, &desc, atm->octrees_storage);
+ if(res != RES_OK) goto error;
+
+ /* The octrees must be loaded from storage. Verify that the data and settings
+ * used by the saved octrees are the same as the current parameters */
+ } else {
+ struct octrees_storage_desc saved_desc;
+ res = read_octrees_storage_desc(atm, &saved_desc, args->octrees_storage);
+ if(res != RES_OK) goto error;
+ if(!octrees_storage_desc_eq(&desc, &saved_desc)) {
+ log_err(atm,
+ "unable to load octrees from the supplied storage. The saved "
+ "octrees are built from different data\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
create_storage_toc(struct rnatm* atm, fpos_t* toc)
{
int err = 0;
@@ -1255,10 +1296,6 @@ build_octrees
ATOMIC res = RES_OK;
ASSERT(atm && args && pool);
- res = svx_device_create
- (atm->logger, &atm->svx_allocator, atm->verbose, &atm->svx);
- if(res != RES_OK) goto error;
-
/* Recover the AABB from the atmosphere. Note that we have already made sure
* when setting up the meshes of the gas and aerosols that the aerosols are
* included in the gas. Therefore, the AABB of the gas is the same as the
@@ -1416,8 +1453,6 @@ create_octrees
res = create_pool(atm, &pool, nbands);
if(res != RES_OK) goto error;
- res = setup_accel_structs(atm, bands);
- if(res != RES_OK) goto error;
res = build_sync_init(&sync);
if(res != RES_OK) goto error;
@@ -1464,13 +1499,29 @@ error:
goto exit;
}
+static INLINE res_T
+load_octrees(struct rnatm* atm)
+{
+ res_T res = RES_OK;
+ ASSERT(atm && atm->octrees_storage);
+
+ /* Only load the storage table of content. The octrees will be loaded on
+ * demand */
+ res = read_octrees_storage_toc(atm, atm->octrees_storage);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
res_T
setup_octrees(struct rnatm* atm, const struct rnatm_create_args* args)
{
- struct octrees_storage_desc desc;
char buf[128];
size_t bands[2];
struct time t0, t1;
@@ -1481,6 +1532,11 @@ setup_octrees(struct rnatm* atm, const struct rnatm_create_args* args)
/* Start time recording */
time_current(&t0);
+ /* Create the Star-VoXel device */
+ res = svx_device_create
+ (atm->logger, &atm->svx_allocator, atm->verbose, &atm->svx);
+ if(res != RES_OK) goto error;
+
/* Setup miscellaneous parameters */
atm->spectral_range[0] = args->spectral_range[0];
atm->spectral_range[1] = args->spectral_range[1];
@@ -1489,18 +1545,24 @@ setup_octrees(struct rnatm* atm, const struct rnatm_create_args* args)
res = compute_grid_definition(atm, args);
if(res != RES_OK) goto error;
- if(atm->octrees_storage) {
- res = setup_octrees_storage_desc(atm, &desc);
- if(res != RES_OK) goto error;
- res = write_octrees_storage_desc(atm, &desc, atm->octrees_storage);
- if(res != RES_OK) goto error;
- }
+ /* Initialize storage *after* calculating the grid definition since it is
+ * saved in the storage file */
+ res = init_octrees_storage(atm, args);
+ if(res != RES_OK) goto error;
res = find_band_range(atm, atm->spectral_range, bands);
if(res != RES_OK) goto error;
- res = create_octrees(atm, args, bands);
+ res = setup_accel_structs(atm, bands);
if(res != RES_OK) goto error;
+ if(args->load_octrees_from_storage) {
+ res = load_octrees(atm);
+ if(res != RES_OK) goto error;
+ } else {
+ res = create_octrees(atm, args, bands);
+ if(res != RES_OK) goto error;
+ }
+
/* Log elapsed time */
time_sub(&t0, time_current(&t1), &t0);
time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf));
diff --git a/src/rnatm_octrees_storage.c b/src/rnatm_octrees_storage.c
@@ -238,6 +238,22 @@ error:
}
res_T
+octrees_storage_desc_eq
+ (const struct octrees_storage_desc* desc0,
+ const struct octrees_storage_desc* desc1)
+{
+ ASSERT(desc0 && desc1);
+ return desc0->spectral_range[0] == desc1->spectral_range[0]
+ && desc0->spectral_range[1] == desc1->spectral_range[1]
+ && desc0->optical_thickness == desc1->optical_thickness
+ && desc0->grid_definition[0] == desc1->grid_definition[0]
+ && desc0->grid_definition[1] == desc1->grid_definition[1]
+ && desc0->grid_definition[2] == desc1->grid_definition[2]
+ && hash256_eq(desc0->signature, desc1->signature)
+ && desc0->version == desc1->version;
+}
+
+res_T
read_octrees_storage_desc
(const struct rnatm* atm,
struct octrees_storage_desc* desc,
@@ -259,6 +275,10 @@ read_octrees_storage_desc
} \
} (void)0
READ(&desc->version, 1);
+ if(desc->version != OCTREES_STORAGE_VERSION) { /* Basic versioning */
+ res = RES_BAD_ARG;
+ goto error;
+ }
READ(desc->spectral_range, 2);
READ(&desc->optical_thickness, 1);
READ(desc->grid_definition, 3);
@@ -268,7 +288,8 @@ read_octrees_storage_desc
exit:
return res;
error:
- log_err(atm, "unable to read tree storage descriptor\n");
+ log_err(atm, "unable to read tree storage descriptor -- %s\n",
+ res_to_cstr(res));
goto exit;
}
@@ -329,17 +350,54 @@ write_octrees_storage_toc(const struct rnatm* atm, FILE* stream)
exit:
return res;
error:
- log_err(atm, "error writing octree table of content\n");
+ log_err(atm, "error writing octree storage table of content -- %s\n",
+ res_to_cstr(res));
goto exit;
}
res_T
-read_octrees_storage_toc(const struct rnatm* atm, FILE* stream)
+read_octrees_storage_toc(struct rnatm* atm, FILE* stream)
{
- /* TODO */
- (void)atm, (void)stream;
- FATAL("Not implemented\n");
- return RES_BAD_OP;
+ size_t noctrees = 0;
+ size_t ioctree = 0;
+ res_T res = RES_OK;
+ ASSERT(atm && stream);
+
+ noctrees = darray_accel_struct_size_get(&atm->accel_structs);
+
+ #define READ(Var) { \
+ if(fread((Var), sizeof(*(Var)), (1), stream) != (1)) { \
+ if(feof(stream)) { \
+ res = RES_BAD_ARG; \
+ } else if(ferror(stream)) { \
+ res = RES_IO_ERR; \
+ } else { \
+ res = RES_UNKNOWN_ERR; \
+ } \
+ goto error; \
+ } \
+ } (void)0
+
+ /* Read the number of toc entries and check that it matches to expected one */
+ READ(&noctrees);
+ if(noctrees != darray_accel_struct_size_get(&atm->accel_structs)) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ FOR_EACH(ioctree, 0, noctrees) {
+ struct accel_struct* accel_struct =
+ darray_accel_struct_data_get(&atm->accel_structs) + ioctree;
+ READ(&accel_struct->fpos);
+ }
+
+ #undef READ
+
+exit:
+ return res;
+error:
+ log_err(atm, "error reading octree storage table of content -- %s\n",
+ res_to_cstr(res));
+ goto exit;
}
extern LOCAL_SYM res_T
diff --git a/src/rnatm_octrees_storage.h b/src/rnatm_octrees_storage.h
@@ -45,6 +45,11 @@ setup_octrees_storage_desc
(const struct rnatm* atm,
struct octrees_storage_desc* desc);
+extern LOCAL_SYM int
+octrees_storage_desc_eq
+ (const struct octrees_storage_desc* desc0,
+ const struct octrees_storage_desc* desc1);
+
extern LOCAL_SYM res_T
write_octrees_storage_desc
(const struct rnatm* atm,
@@ -69,7 +74,7 @@ write_octrees_storage_toc
extern LOCAL_SYM res_T
read_octrees_storage_toc
- (const struct rnatm* atm,
+ (struct rnatm* atm,
FILE* stream);
extern LOCAL_SYM res_T
diff --git a/src/test_rnatm.c b/src/test_rnatm.c
@@ -80,6 +80,8 @@ print_help(const char* cmd)
printf(
" -h display this help and exit\n");
printf(
+" -i file octrees are loaded from file\n");
+ printf(
" -N precompute_normals the tetrahedra normals\n");
printf(
" -o file offload octrees to file\n");
@@ -335,7 +337,7 @@ args_init(struct args* args, int argc, char** argv)
*args = ARGS_DEFAULT;
- while((opt = getopt(argc, argv, "a:d:g:hNo:s:T:t:V:v")) != -1) {
+ while((opt = getopt(argc, argv, "a:d:g:hi:No:s:T:t:V:v")) != -1) {
switch(opt) {
case 'a':
sa_add(args->rnatm.aerosols, 1);
@@ -353,7 +355,14 @@ args_init(struct args* args, int argc, char** argv)
args->quit = 1;
goto exit;
case 'N': args->rnatm.precompute_normals = 1; break;
- case 'o': storage_filename = optarg; break;
+ case 'o':
+ args->rnatm.load_octrees_from_storage = 0;
+ storage_filename = optarg;
+ break;
+ case 'i':
+ args->rnatm.load_octrees_from_storage = 1;
+ storage_filename = optarg;
+ break;
case 's':
res = parse_spectral_range(args, optarg);
break;
@@ -382,7 +391,8 @@ args_init(struct args* args, int argc, char** argv)
}
if(storage_filename) {
- args->rnatm.octrees_storage = fopen(storage_filename, "w+");
+ const char* mode = args->rnatm.load_octrees_from_storage ? "r" : "w+";
+ args->rnatm.octrees_storage = fopen(storage_filename, mode);
if(!args->rnatm.octrees_storage) {
fprintf(stderr, "Unable to open octree storage file %s\n",
storage_filename);