commit d4296b6f2ccc4c90f0706064ac5792a8ae615b0e
parent 3bc37e0e15640ce3ce1021d3f612e3afe42a5812
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 20 Feb 2020 13:02:33 +0100
Add cache support
The cache is used to store/restore the acceleration data structures of
the sky. These structures are actually quite fast to build but the data
onto which they rely are expensive to evaluate leading to excessive
pre-processing computation time.
Diffstat:
5 files changed, 402 insertions(+), 82 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -29,7 +29,7 @@ find_package(OpenMP 1.2 REQUIRED)
find_package(RCMake 0.3 REQUIRED)
find_package(RSys 0.7 REQUIRED)
find_package(StarMTL)
-find_package(StarVX REQUIRED)
+find_package(StarVX 0.1 REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
include(rcmake)
diff --git a/src/htsky.c b/src/htsky.c
@@ -14,6 +14,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#define _POSIX_C_SOURCE 200809L /* stat.st_time support */
+
#include "htsky.h"
#include "htsky_c.h"
#include "htsky_atmosphere.h"
@@ -29,6 +31,11 @@
#include <rsys/clock_time.h>
#include <rsys/double3.h>
+#include <errno.h>
+#include <fcntl.h> /* open */
+#include <unistd.h>
+#include <sys/stat.h> /* S_IRUSR & S_IWUSR */
+
#include <omp.h>
/*******************************************************************************
@@ -116,6 +123,140 @@ sample_sw_spectral_data
HTGOP(spectral_interval_sample_quadrature(&specint, r1, iquadrature_pt));
}
+static res_T
+setup_cache_stream
+ (struct htsky* sky,
+ const char* htcp_filename,
+ const char* htgop_filename,
+ const char* htmie_filename,
+ const char* cache_filename,
+ int* out_create_cache, /* Define if the cache file was created */
+ FILE** out_fp)
+{
+ FILE* fp = NULL;
+ struct stat htcp_statbuf;
+ struct stat htgop_statbuf;
+ struct stat htmie_statbuf;
+ int create_cache = 0;
+ int fd = -1;
+ res_T res = RES_OK;
+ ASSERT(sky && out_create_cache && out_fp);
+ ASSERT(htcp_filename && htgop_filename && htmie_filename && cache_filename);
+
+ /* Open the cache file */
+ fd = open(cache_filename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
+ if(fd >= 0) {
+ create_cache = 1;
+ } else if (errno == EEXIST) { /* The cache already exists */
+ fd = open(cache_filename, O_RDWR, 0);
+ }
+
+ if(fd < 0) {
+ log_err(sky, "unexpected error while opening the cache file `%s'.\n",
+ cache_filename);
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ fp = fdopen(fd, "w+");
+ if(!fp) {
+ log_err(sky, "could not open the cache file `%s'.\n", cache_filename);
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ /* Query the status of the input */
+ #define STAT(Filename, Statbuf) { \
+ const int err = stat(Filename, Statbuf); \
+ if(err) { \
+ log_err(sky, "%s: could not stat the file -- %s\n", \
+ Filename, strerror(errno)); \
+ res = RES_IO_ERR; \
+ goto error; \
+ } \
+ } (void)0
+ STAT(htcp_filename, &htcp_statbuf);
+ STAT(htgop_filename, &htgop_statbuf);
+ STAT(htmie_filename, &htmie_statbuf);
+ #undef STAT
+
+ if(create_cache) {
+ /* Setup the cache header, i.e. data that uniquely identify the cache
+ * regarding the input files (htcp, htmie and htgop files) */
+ #define WRITE(Var, N) { \
+ if(fwrite((Var), sizeof(*(Var)), (N), fp) != (N)) { \
+ log_err(sky, "%s: could not write the cache header.\n",cache_filename);\
+ res = RES_IO_ERR; \
+ goto error; \
+ } \
+ } (void)0
+ WRITE(&htcp_statbuf.st_ino, 1);
+ WRITE(&htcp_statbuf.st_mtim, 1);
+ WRITE(&htgop_statbuf.st_ino, 1);
+ WRITE(&htgop_statbuf.st_mtim, 1);
+ WRITE(&htmie_statbuf.st_ino, 1);
+ WRITE(&htmie_statbuf.st_mtim, 1);
+ #undef WRITE
+ CHK(fflush(fp) == 0);
+ } else {
+ struct stat htcp_statbuf2;
+ struct stat htgop_statbuf2;
+ struct stat htmie_statbuf2;
+
+ /* Read the cache header */
+ #define READ(Var, N) { \
+ if(fread((Var), sizeof(*(Var)), (N), fp) != (N)) { \
+ if(feof(fp)) { \
+ res = RES_BAD_ARG; \
+ } else if(ferror(fp)) { \
+ res = RES_IO_ERR; \
+ } else { \
+ res = RES_UNKNOWN_ERR; \
+ } \
+ log_err(sky, "%s: could not read the cache header.\n",cache_filename); \
+ goto error; \
+ } \
+ } (void)0
+ READ(&htcp_statbuf2.st_ino, 1);
+ READ(&htcp_statbuf2.st_mtim, 1);
+ READ(&htgop_statbuf2.st_ino, 1);
+ READ(&htgop_statbuf2.st_mtim, 1);
+ READ(&htmie_statbuf2.st_ino, 1);
+ READ(&htmie_statbuf2.st_mtim, 1);
+ #undef READ
+
+ /* Compare the cache header with the input file status to check that the
+ * cached data matched the input data */
+ #define CHK_STAT(Stat0, Stat1) { \
+ if((Stat0)->st_ino != (Stat1)->st_ino \
+ || (Stat0)->st_mtim.tv_sec != (Stat1)->st_mtim.tv_sec \
+ || (Stat0)->st_mtim.tv_nsec != (Stat1)->st_mtim.tv_nsec) { \
+ log_err(sky, "%s: invalid cache regarding the input files.\n", \
+ cache_filename); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } \
+ } (void)0
+ CHK_STAT(&htcp_statbuf, &htcp_statbuf2);
+ CHK_STAT(&htgop_statbuf, &htgop_statbuf2);
+ CHK_STAT(&htmie_statbuf, &htmie_statbuf2);
+ #undef CHK_STAT
+ }
+
+exit:
+ *out_fp = fp;
+ *out_create_cache = create_cache;
+ return res;
+error:
+ if(fp) {
+ CHK(fclose(fp) == 0);
+ fp = NULL;
+ } else if(fd >= 0) {
+ CHK(close(fd) == 0);
+ }
+ goto exit;
+}
+
static void
release_sky(ref_T* ref)
{
@@ -151,6 +292,8 @@ htsky_create
struct htsky* sky = NULL;
char buf[128];
int nthreads_max;
+ int force_cache_upd = 0;
+ FILE* cache = NULL;
res_T res = RES_OK;
if(!check_args(args) || !out_sky) {
@@ -280,8 +423,15 @@ htsky_create
goto error;
}
+ if(args->cache_filename) {
+ res = setup_cache_stream(sky, args->htcp_filename, args->htgop_filename,
+ args->htmie_filename, args->cache_filename, &force_cache_upd, &cache);
+ if(res != RES_OK) goto error;
+ }
+
time_current(&t0);
- res = cloud_setup(sky, args->grid_max_definition, args->optical_thickness);
+ res = cloud_setup(sky, args->grid_max_definition, args->optical_thickness,
+ args->cache_filename, force_cache_upd, cache);
if(res != RES_OK) goto error;
time_sub(&t0, time_current(&t1), &t0);
time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf));
@@ -292,6 +442,7 @@ htsky_create
}
exit:
+ if(cache) fclose(cache);
*out_sky = sky;
return res;
error:
diff --git a/src/htsky.h b/src/htsky.h
@@ -67,6 +67,7 @@ struct htsky_args {
const char* htcp_filename;
const char* htgop_filename;
const char* htmie_filename;
+ const char* cache_filename; /* May be NULL <=> no cached data structure */
const char* name; /* Name of the sky. Used by the Star-MTL binding */
unsigned grid_max_definition[3]; /* Maximum definition of the grid */
double optical_thickness; /* Threshold used during octree building */
@@ -79,6 +80,7 @@ struct htsky_args {
NULL, /* htcp_filename */ \
NULL, /* htgop_filename */ \
NULL, /* htmie filename */ \
+ NULL, /* cache filename */ \
"sky", /* Name */ \
{UINT_MAX, UINT_MAX, UINT_MAX}, /* Maximum definition of the grid */ \
1, /* Optical thickness a*/ \
diff --git a/src/htsky_cloud.c b/src/htsky_cloud.c
@@ -22,6 +22,7 @@
#include "htsky_svx.h"
#include <high_tune/htgop.h>
+#include <rsys/cstr.h>
#include <rsys/dynamic_array.h>
#include <star/svx.h>
@@ -592,6 +593,206 @@ cloud_vox_challenge_merge
&& vox_challenge_merge_component(HTSKY_CPNT_GAS, voxels, nvoxs, ctx);
}
+static res_T
+cloud_build_octrees
+ (struct htsky* sky,
+ const double low[3], /* Lower bound of the clouds */
+ const double upp[3], /* Upper bound of the clouds */
+ const unsigned grid_max_definition[3],
+ const double optical_thickness_threshold,
+ struct darray_specdata* specdata)
+{
+ double vxsz[3] = {0, 0, 0};
+ size_t nvoxs[3] = {0, 0, 0};
+ const size_t* raw_def = NULL;
+ int64_t ispecdata;
+ int64_t nspecdata;
+ int32_t progress;
+ ATOMIC nbuilt_octrees = 0;
+ ATOMIC res = RES_OK;
+ ASSERT(sky && specdata);
+ ASSERT(low && upp && grid_max_definition);
+ ASSERT(low[0] < upp[0]);
+ ASSERT(low[1] < upp[1]);
+ ASSERT(low[2] < upp[2]);
+ ASSERT(grid_max_definition[0]);
+ ASSERT(grid_max_definition[1]);
+ ASSERT(grid_max_definition[2]);
+ ASSERT(optical_thickness_threshold >= 0);
+
+ progress = 0;
+ nspecdata = (int64_t)darray_specdata_size_get(specdata);
+
+ /* Define the number of voxels */
+ raw_def = sky->htcp_desc.spatial_definition;
+ nvoxs[0] = MMIN(raw_def[0], grid_max_definition[0]);
+ nvoxs[1] = MMIN(raw_def[1], grid_max_definition[1]);
+ nvoxs[2] = MMIN(raw_def[2], grid_max_definition[2]);
+
+ /* Setup the build context */
+ vxsz[0] = sky->htcp_desc.upper[0] - sky->htcp_desc.lower[0];
+ vxsz[1] = sky->htcp_desc.upper[1] - sky->htcp_desc.lower[1];
+ vxsz[2] = sky->htcp_desc.upper[2] - sky->htcp_desc.lower[2];
+ vxsz[0] = vxsz[0] / (double)nvoxs[0];
+ vxsz[1] = vxsz[1] / (double)nvoxs[1];
+ vxsz[2] = vxsz[2] / (double)nvoxs[2];
+
+ omp_set_num_threads((int)sky->nthreads);
+ #define LOG_MSG "\033[2K\rComputing clouds data & building octrees: %3d%%"
+ log_info(sky, LOG_MSG, 0);
+ #pragma omp parallel for schedule(dynamic, 1/*chunksize*/)
+ for(ispecdata=0; ispecdata < nspecdata; ++ispecdata) {
+ struct svx_voxel_desc vox_desc = SVX_VOXEL_DESC_NULL;
+ struct build_tree_context ctx = BUILD_TREE_CONTEXT_NULL;
+ const size_t iband = darray_specdata_data_get(specdata)[ispecdata].iband;
+ const size_t iquad = darray_specdata_data_get(specdata)[ispecdata].iquad;
+ const size_t id = iband - sky->sw_bands_range[0];
+ int32_t pcent;
+ size_t n;
+ res_T res_local = RES_OK;
+
+ if(ATOMIC_GET(&res) != RES_OK) continue;
+
+ /* The current octree could be already setup from a cache and the
+ * invocation of the current function remains is still valid. Indeed, if
+ * some octrees could not be restore from the cache, one can choose to
+ * build them from scratch rather than rejecting the whole process. */
+ if(sky->clouds[id][iquad].octree) continue;
+
+ /* Setup the build context */
+ ctx.sky = sky;
+ ctx.vxsz[0] = vxsz[0];
+ ctx.vxsz[1] = vxsz[1];
+ ctx.vxsz[2] = vxsz[2];
+ ctx.tau_threshold = optical_thickness_threshold;
+ ctx.iband = iband;
+ ctx.quadrature_range[0] = iquad;
+ ctx.quadrature_range[1] = iquad;
+
+ /* Setup the voxel descriptor */
+ vox_desc.get = cloud_vox_get;
+ vox_desc.merge = cloud_vox_merge;
+ vox_desc.challenge_merge = cloud_vox_challenge_merge;
+ vox_desc.context = &ctx;
+ vox_desc.size = sizeof(float) * NFLOATS_PER_VOXEL;
+
+ /* Create the octree */
+ res_local = svx_octree_create
+ (sky->svx, low, upp, nvoxs, &vox_desc, &sky->clouds[id][iquad].octree);
+
+ if(res_local != RES_OK) {
+ log_err(sky,
+ "Could not create the octree of the cloud properties for the band %lu.\n",
+ (unsigned long)ctx.iband);
+ ATOMIC_SET(&res, res_local);
+ continue;
+ }
+
+ /* Fetch the octree descriptor for future use */
+ SVX(tree_get_desc
+ (sky->clouds[id][iquad].octree, &sky->clouds[id][iquad].octree_desc));
+
+ /* Update the progress message */
+ n = (size_t)ATOMIC_INCR(&nbuilt_octrees);
+ pcent = (int32_t)(n * 100 / darray_specdata_size_get(specdata));
+
+ #pragma omp critical
+ if(pcent > progress) {
+ progress = pcent;
+ log_info(sky, LOG_MSG, pcent);
+ }
+ }
+
+ if(res != RES_OK)
+ goto error;
+
+ log_info(sky, LOG_MSG"\n", 100);
+ #undef LOG_MSG
+
+exit:
+ return (res_T)res;
+error:
+ goto exit;
+}
+
+static res_T
+cloud_write_octrees(const struct htsky* sky, FILE* stream)
+{
+ size_t nbands;
+ size_t i;
+ res_T res = RES_OK;
+ ASSERT(sky && sky->clouds);
+
+ nbands = htsky_get_sw_spectral_bands_count(sky);
+ FOR_EACH(i, 0, nbands) {
+ struct htgop_spectral_interval band;
+ size_t iband;
+ size_t iquad;
+
+ iband = sky->sw_bands_range[0] + i;
+ HTGOP(get_sw_spectral_interval(sky->htgop, iband, &band));
+ ASSERT(sky->clouds[i]);
+
+ FOR_EACH(iquad, 0, band.quadrature_length) {
+ ASSERT(sky->clouds[i][iquad].octree);
+ res = svx_tree_write(sky->clouds[i][iquad].octree, stream);
+ if(res != RES_OK) {
+ log_err(sky, "Could not write the octrees of the clouds.\n");
+ goto error;
+ }
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+cloud_read_octrees(struct htsky* sky, const char* stream_name, FILE* stream)
+{
+ size_t nbands;
+ size_t i;
+ res_T res = RES_OK;
+ ASSERT(sky && sky->clouds && stream_name);
+
+ log_info(sky, "Loading octrees from `%s'.\n", stream_name);
+ nbands = htsky_get_sw_spectral_bands_count(sky);
+ FOR_EACH(i, 0, nbands) {
+ struct htgop_spectral_interval band;
+ size_t iband;
+ size_t iquad;
+
+ iband = sky->sw_bands_range[0] + i;
+ HTGOP(get_sw_spectral_interval(sky->htgop, iband, &band));
+ ASSERT(sky->clouds[i]);
+
+ FOR_EACH(iquad, 0, band.quadrature_length) {
+ /* The octree was already setup */
+ if(sky->clouds[i][iquad].octree != NULL) continue;
+
+ res = svx_tree_create_from_stream
+ (sky->svx, stream, &sky->clouds[i][iquad].octree);
+ if(res != RES_OK) {
+ log_err(sky, "Could not read the octree %lu:%lu from `%s' -- %s.\n",
+ (unsigned long)iband, (unsigned long)iquad, stream_name,
+ res_to_cstr(res));
+ goto error;
+ }
+
+ /* Fetch the octree descriptor for future use */
+ SVX(tree_get_desc
+ (sky->clouds[i][iquad].octree, &sky->clouds[i][iquad].octree_desc));
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
@@ -599,22 +800,23 @@ res_T
cloud_setup
(struct htsky* sky,
const unsigned grid_max_definition[3],
- const double optical_thickness_threshold)
+ const double optical_thickness_threshold,
+ const char* cache_name,
+ const int force_cache_update,
+ FILE* cache)
{
struct darray_specdata specdata;
const size_t* raw_def;
- size_t nvoxs[3];
- double vxsz[3];
double low[3];
double upp[3];
- int64_t ispecdata;
- int32_t progress;
size_t nbands;
size_t i;
- ATOMIC nbuilt_octrees = 0;
ATOMIC res = RES_OK;
- ASSERT(grid_max_definition);
ASSERT(sky && sky->sw_bands && optical_thickness_threshold >= 0);
+ ASSERT(grid_max_definition);
+ ASSERT(grid_max_definition[0]);
+ ASSERT(grid_max_definition[1]);
+ ASSERT(grid_max_definition[2]);
darray_specdata_init(sky->allocator, &specdata);
@@ -629,9 +831,6 @@ cloud_setup
/* Define the number of voxels */
raw_def = sky->htcp_desc.spatial_definition;
- nvoxs[0] = MMIN(raw_def[0], grid_max_definition[0]);
- nvoxs[1] = MMIN(raw_def[1], grid_max_definition[1]);
- nvoxs[2] = MMIN(raw_def[2], grid_max_definition[2]);
/* Define the octree AABB excepted for the Z dimension */
low[0] = sky->htcp_desc.lower[0];
@@ -649,14 +848,6 @@ cloud_setup
if(res != RES_OK) goto error;
}
- /* Setup the build context */
- vxsz[0] = sky->htcp_desc.upper[0] - sky->htcp_desc.lower[0];
- vxsz[1] = sky->htcp_desc.upper[1] - sky->htcp_desc.lower[1];
- vxsz[2] = sky->htcp_desc.upper[2] - sky->htcp_desc.lower[2];
- vxsz[0] = vxsz[0] / (double)nvoxs[0];
- vxsz[1] = vxsz[1] / (double)nvoxs[1];
- vxsz[2] = vxsz[2] / (double)nvoxs[2];
-
/* Create as many cloud data structure than considered SW spectral bands */
nbands = htsky_get_sw_spectral_bands_count(sky);
sky->clouds = MEM_CALLOC(sky->allocator, nbands, sizeof(*sky->clouds));
@@ -679,7 +870,7 @@ cloud_setup
band.quadrature_length, sizeof(*sky->clouds[i]));
if(!sky->clouds[i]) {
log_err(sky,
- "could not create the list of per quadrature point cloud data "
+ "Could not create the list of per quadrature point cloud data "
"for the band %lu.\n", (unsigned long)iband);
res = RES_MEM_ERR;
goto error;
@@ -692,77 +883,51 @@ cloud_setup
res = darray_specdata_push_back(&specdata, &spectral_data);
if(res != RES_OK) {
log_err(sky,
- "could not register the quadrature point %lu of the spectral band "
+ "Could not register the quadrature point %lu of the spectral band "
"%lu .\n", (unsigned long)iband, (unsigned long)iquad);
goto error;
}
}
}
- progress = 0;
- omp_set_num_threads((int)sky->nthreads);
- #define LOG_MSG "\033[2K\rComputing clouds data & building octrees: %3d%%"
- log_info(sky, LOG_MSG, 0);
- #pragma omp parallel for schedule(dynamic, 1/*chunksize*/)
- for(ispecdata=0;
- (size_t)ispecdata<darray_specdata_size_get(&specdata);
- ++ispecdata) {
- struct svx_voxel_desc vox_desc = SVX_VOXEL_DESC_NULL;
- struct build_tree_context ctx = BUILD_TREE_CONTEXT_NULL;
- const size_t iband = darray_specdata_data_get(&specdata)[ispecdata].iband;
- const size_t iquad = darray_specdata_data_get(&specdata)[ispecdata].iquad;
- const size_t id = iband - sky->sw_bands_range[0];
- int32_t pcent;
- size_t n;
- res_T res_local = RES_OK;
-
- if(ATOMIC_GET(&res) != RES_OK) continue;
-
- /* Setup the build context */
- ctx.sky = sky;
- ctx.vxsz[0] = vxsz[0];
- ctx.vxsz[1] = vxsz[1];
- ctx.vxsz[2] = vxsz[2];
- ctx.tau_threshold = optical_thickness_threshold;
- ctx.iband = iband;
- ctx.quadrature_range[0] = iquad;
- ctx.quadrature_range[1] = iquad;
-
- /* Setup the voxel descriptor */
- vox_desc.get = cloud_vox_get;
- vox_desc.merge = cloud_vox_merge;
- vox_desc.challenge_merge = cloud_vox_challenge_merge;
- vox_desc.context = &ctx;
- vox_desc.size = sizeof(float) * NFLOATS_PER_VOXEL;
+ if(!cache) { /* No cache => build the octrees from scratch */
+ res = cloud_build_octrees(sky, low, upp, grid_max_definition,
+ optical_thickness_threshold, &specdata);
+ if(res != RES_OK) goto error;
- /* Create the octree */
- res_local = svx_octree_create
- (sky->svx, low, upp, nvoxs, &vox_desc, &sky->clouds[id][iquad].octree);
+ } else if(force_cache_update) {
+ /* Build the octrees from scratch */
+ res = cloud_build_octrees(sky, low, upp, grid_max_definition,
+ optical_thickness_threshold, &specdata);
+ if(res != RES_OK) goto error;
- if(res_local != RES_OK) {
- log_err(sky,
- "could not create the octree of the cloud properties for the band %lu.\n",
- (unsigned long)ctx.iband);
- ATOMIC_SET(&res, res_local);
- continue;
- }
+ /* Write the octrees into the cache stream */
+ res = cloud_write_octrees(sky, cache);
+ if(res != RES_OK) goto error;
- /* Fetch the octree descriptor for future use */
- SVX(tree_get_desc
- (sky->clouds[id][iquad].octree, &sky->clouds[id][iquad].octree_desc));
+ } else {
+ const long offset = ftell(cache);
+
+ /* Try to load the octrees from the cache */
+ res = cloud_read_octrees(sky, cache_name, cache);
+ if(res != RES_OK) {
+ const int err = fseek(cache, offset, SEEK_SET); /* Restore the stream */
+ if(err) {
+ log_err(sky, "Could not restore the cache stream.\n");
+ res = RES_IO_ERR;
+ goto error;
+ }
- /* Update the progress message */
- n = (size_t)ATOMIC_INCR(&nbuilt_octrees);
- pcent = (int32_t)(n * 100 / darray_specdata_size_get(&specdata));
+ /* Build the octrees from scratch */
+ res = cloud_build_octrees(sky, low, upp, grid_max_definition,
+ optical_thickness_threshold, &specdata);
+ if(res != RES_OK) goto error;
- #pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(sky, LOG_MSG, pcent);
+ /* Write the octrees toward the cache stream */
+ res = cloud_write_octrees(sky, cache);
+ if(res != RES_OK) goto error;
}
}
- log_info(sky, LOG_MSG"\n", 100);
- #undef LOG_MSG
exit:
darray_specdata_release(&specdata);
@@ -805,4 +970,3 @@ cloud_clean(struct htsky* sky)
sky->clouds = NULL;
}
-
diff --git a/src/htsky_cloud.h b/src/htsky_cloud.h
@@ -29,8 +29,11 @@ struct cloud {
extern LOCAL_SYM res_T
cloud_setup
(struct htsky* sky,
- const unsigned grid_max_definition[3],
- const double optical_thickness_threshold);
+ const unsigned grid_max_definition[3], /* Ignore when the cache is used */
+ const double optical_thickness_threshold, /* Ingore when the cache is used */
+ const char* cache_name, /* Name of the stream where octrees are stored */
+ const int force_cache_update, /* Force upd of the stream storing the octrees */
+ FILE* cache); /* Stream where octrees are written/read. May be NULL */
extern LOCAL_SYM void
cloud_clean