star-mc

Parallel estimation of Monte Carlo integrators
git clone git://git.meso-star.fr/star-mc.git
Log | Files | Refs | README | LICENSE

commit 1f624d506b3978b9681b523d18cec60a260b8d93
parent ac7c9edf63de832c06b6059845f18a2561d98bc4
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  8 Apr 2015 11:17:37 +0200

Add the max_<steps|time> parameters to the smc_solve function

Diffstat:
Msrc/smc.h | 19+++++++++++++++----
Msrc/smc_integrator.c | 51+++++++++++++++++++++++++++++++++++++--------------
Msrc/test_smc_light_path.c | 50+++++++++++++++++++++++++++++++++++++-------------
Msrc/test_smc_solve.c | 40++++++++++++++++++++++------------------
4 files changed, 111 insertions(+), 49 deletions(-)

diff --git a/src/smc.h b/src/smc.h @@ -33,6 +33,7 @@ #define SMC_H #include <rsys/rsys.h> +#include <limits.h> /* Library symbol management */ #if defined(SMC_SHARED_BUILD) /* Build shared library */ @@ -71,6 +72,10 @@ struct smc_type { void (*sqrt)(void* result, const void* value); }; +static const struct smc_type SMC_TYPE_NULL = +{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + + struct smc_estimator_status { void* E; /* Expected value */ void* V; /* Variance */ @@ -78,8 +83,15 @@ struct smc_estimator_status { unsigned long N; /* Samples count */ }; -static const struct smc_type smc_type_null = -{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +struct smc_integrator { + void (*integrand)(void* value, struct ssp_rng* rng, void* ctx); + const struct smc_type* type; + unsigned long max_steps; /* Maximum # of experiments */ + unsigned long max_time; /* Hint on the maximum time in micro seconds */ +}; + +static const struct smc_integrator SMC_INTEGRATOR_NULL = +{ NULL, NULL, ULONG_MAX, ULONG_MAX }; /* Forward declaration of opaque types */ struct smc_device; /* Entry point of the library */ @@ -115,8 +127,7 @@ smc_device_ref_put SMC_API res_T smc_solve (struct smc_device* dev, - void (*integrand)(void* value, struct ssp_rng* rng, void* ctx), - const struct smc_type* type, + struct smc_integrator* integrator, void* ctx, struct smc_estimator** estimator); diff --git a/src/smc_integrator.c b/src/smc_integrator.c @@ -33,6 +33,7 @@ #include "smc_device_c.h" #include "smc_type_c.h" +#include <rsys/clock_time.h> #include <rsys/mem_allocator.h> #include <limits.h> @@ -52,6 +53,17 @@ struct smc_estimator { /******************************************************************************* * Helper functions ******************************************************************************/ +static char +check_integrator(struct smc_integrator* integrator) +{ + ASSERT(integrator); + return integrator->integrand + && integrator->type + && integrator->max_steps + && integrator->max_time + && check_type(integrator->type); +} + static void estimator_release(ref_T* ref) { @@ -81,17 +93,17 @@ estimator_release(ref_T* ref) res_T smc_solve (struct smc_device* dev, - void (*integrand)(void* value, struct ssp_rng* rng, void* ctx), - const struct smc_type* type, + struct smc_integrator* integrator, void* ctx, struct smc_estimator** out_estimator) { struct smc_estimator* estimator = NULL; + struct time time_begin; unsigned long i; void* val = NULL; res_T res = RES_OK; - if(!dev || !integrand || !type || !out_estimator || !check_type(type)) { + if(!dev || !integrator || !out_estimator || !check_integrator(integrator)) { res = RES_BAD_ARG; goto error; } @@ -106,12 +118,12 @@ smc_solve ref_init(&estimator->ref); #define TYPE_CREATE(Dst) { \ - (Dst) = type->create(dev->allocator); \ + (Dst) = integrator->type->create(dev->allocator); \ if(!(Dst)) { \ res = RES_MEM_ERR; \ goto error; \ } \ - type->zero((Dst)); \ + integrator->type->zero((Dst)); \ } (void)0 TYPE_CREATE(estimator->value); TYPE_CREATE(estimator->square_value); @@ -122,17 +134,28 @@ smc_solve #undef TYPE_CREATE estimator->nsamples = 0; estimator->status.N = 0; - estimator->type = *type; - - FOR_EACH(i, 0, 16) { - if(estimator->nsamples == ULONG_MAX) break; - integrand(val, dev->rng, ctx); - type->add(estimator->value, estimator->value, val); - type->mul(val, val, val); - type->add(estimator->square_value, estimator->square_value, val); + estimator->type = *integrator->type; + + if(integrator->max_time != ULONG_MAX) + time_current(&time_begin); + + FOR_EACH(i, 0, integrator->max_steps) { + struct time elapsed_time; + + integrator->integrand(val, dev->rng, ctx); + integrator->type->add(estimator->value, estimator->value, val); + integrator->type->mul(val, val, val); + integrator->type->add(estimator->square_value, estimator->square_value, val); ++estimator->nsamples; + + if(integrator->max_time != ULONG_MAX) { + time_current(&elapsed_time); + time_sub(&elapsed_time, &elapsed_time, &time_begin); + if((unsigned long)time_val(&elapsed_time, TIME_USEC) > integrator->max_time) + break; + } } - type->destroy(dev->allocator, val); + integrator->type->destroy(dev->allocator, val); exit: if(out_estimator) *out_estimator = estimator; diff --git a/src/test_smc_light_path.c b/src/test_smc_light_path.c @@ -43,10 +43,10 @@ #define IMG_WIDTH 640 #define IMG_HEIGHT 480 -#define LIGHT_PATH_DEPTH 4 -#define SKY_RADIANCE 0.1f -#define ALBEDO 1.f -#define EPSILON 1.e-3f +#define LIGHT_PATH_DEPTH 16 +#define ALBEDO 0.6f +#define EPSILON 1.e-1f +#define GAMMA 2.2 struct cbox_desc{ const float* vertices; @@ -205,13 +205,19 @@ struct integrator_context { static float direct_lighting(struct s3d_scene* scn, const float pos[3], const float N[3]) { - const float light_pos[3] = { 200.f, 0.f, 400.f }; - const float radiance = 20000.f; + const float light_pos[3] = { 200.f, 200.f, 400.f }; + const float flux = 60.0; /* Radiant flux in watt */ + const float intensity = (float)(flux/(4.0*PI)); /*Radiant intensity in W/sr*/ struct s3d_hit hit; float len; float wi[3]; float range[2]; + NCHECK(scn, NULL); + NCHECK(pos, NULL); + NCHECK(N, NULL); + CHECK(f3_is_normalized(N), 1); + f3_sub(wi, light_pos, pos); len = f3_normalize(wi, wi); @@ -219,11 +225,25 @@ direct_lighting(struct s3d_scene* scn, const float pos[3], const float N[3]) range[0] = EPSILON; range[1] = len; CHECK(s3d_scene_trace_ray(scn, pos, wi, range, &hit), RES_OK); + if(!S3D_HIT_NONE(&hit)) return 0.f; /* Light is occluded */ + + len *= 0.01f; /* Transform len from centimer to meter */ + return + intensity / (len*len) /* radiance in W/(sr.m^2) */ + * (float)(ALBEDO / PI) /* BRDF */ + * f3_dot(wi, N); /* cos(wi,N) */ +} - if(!S3D_HIT_NONE(&hit)) - return 0.f; +static float +skydome_lighting(const float wi[3]) +{ + const float ground_irradiance = 0.01f; + const float sky_irradiance = 12.0f; + float u; - return (radiance * (float)(ALBEDO / PI)) / (len*len) * f3_dot(wi, N); + NCHECK(wi, NULL); + u = CLAMP(wi[2], 0.f, 0.05f) * 1.f; + return u * sky_irradiance + (1.f - u) * ground_irradiance; } static void @@ -267,7 +287,7 @@ light_path_integrator(void* value, struct ssp_rng* rng, void* data) (ctx->scn, ray_org, ray_dir, ray_range, &hit), RES_OK); if(S3D_HIT_NONE(&hit)) { /* Skydome lighting */ - L += throughput * SKY_RADIANCE; + L += throughput * skydome_lighting(ray_dir); break; } @@ -304,6 +324,7 @@ main(int argc, char** argv) struct s3d_shape* shape; struct s3d_vertex_data attribs[2]; struct smc_device* smc; + struct smc_integrator integrator = SMC_INTEGRATOR_NULL; unsigned char* img = NULL; size_t ix, iy; float pos[3]; @@ -359,14 +380,17 @@ main(int argc, char** argv) ctx.pixel_size[0] = 1.f / (float)IMG_WIDTH; ctx.pixel_size[1] = 1.f / (float)IMG_HEIGHT; + integrator.integrand = light_path_integrator; + integrator.type = &smc_float; + integrator.max_steps = 1; + FOR_EACH(iy, 0, IMG_HEIGHT) { ctx.ipixel[1] = iy; FOR_EACH(ix, 0, IMG_WIDTH) { struct smc_estimator* estimator; struct smc_estimator_status status; ctx.ipixel[0] = ix; - CHECK(smc_solve - (smc, light_path_integrator, &smc_float, &ctx, &estimator), RES_OK); + CHECK(smc_solve(smc, &integrator, &ctx, &estimator), RES_OK); if(img) { const size_t ipix = (iy*IMG_WIDTH + ix) * 3/*RGB*/; @@ -374,7 +398,7 @@ main(int argc, char** argv) unsigned char colu; CHECK(smc_estimator_get_status(estimator, &status), RES_OK); - col = (float)pow(SMC_FLOAT(status.E), 1.0/2.2); /* Gamma correction */ + col = (float)pow(SMC_FLOAT(status.E), 1.0/GAMMA); /* Gamma correction */ colu = (unsigned char)(CLAMP(col, 0.f, 1.f) * 255.f); /* Float to U8 */ img[ipix + 0] = colu; img[ipix + 1] = colu; diff --git a/src/test_smc_solve.c b/src/test_smc_solve.c @@ -66,6 +66,7 @@ main(int argc, char** argv) { struct mem_allocator allocator; struct smc_device* dev; + struct smc_integrator integrator = SMC_INTEGRATOR_NULL; struct smc_estimator* estimator; struct smc_estimator_status status; (void)argc, (void)argv; @@ -74,23 +75,18 @@ main(int argc, char** argv) CHECK(smc_device_create(NULL, &allocator, &dev), RES_OK); - CHECK(smc_solve(NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(smc_solve(dev, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(smc_solve(NULL, rcp_x, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(smc_solve(dev, rcp_x, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(smc_solve(NULL, NULL, &smc_float, NULL, NULL), RES_BAD_ARG); - CHECK(smc_solve(dev, NULL, &smc_float, NULL, NULL), RES_BAD_ARG); - CHECK(smc_solve(NULL, rcp_x, &smc_float, NULL, NULL), RES_BAD_ARG); - CHECK(smc_solve(dev, rcp_x, &smc_float, NULL, NULL), RES_BAD_ARG); - - CHECK(smc_solve(NULL, NULL, NULL, NULL, &estimator), RES_BAD_ARG); - CHECK(smc_solve(dev, NULL, NULL, NULL, &estimator), RES_BAD_ARG); - CHECK(smc_solve(NULL, rcp_x, NULL, NULL, &estimator), RES_BAD_ARG); - CHECK(smc_solve(dev, rcp_x, NULL, NULL, &estimator), RES_BAD_ARG); - CHECK(smc_solve(NULL, NULL, &smc_double, NULL, &estimator), RES_BAD_ARG); - CHECK(smc_solve(dev, NULL, &smc_double, NULL, &estimator), RES_BAD_ARG); - CHECK(smc_solve(NULL, rcp_x, &smc_double, NULL, &estimator), RES_BAD_ARG); - CHECK(smc_solve(dev, rcp_x, &smc_double, NULL, &estimator), RES_OK); + integrator.integrand = rcp_x; + integrator.type = &smc_double; + integrator.max_steps = 4096; + + CHECK(smc_solve(NULL, NULL, NULL, NULL), RES_BAD_ARG); + CHECK(smc_solve(dev, NULL, NULL, NULL), RES_BAD_ARG); + CHECK(smc_solve(NULL, &integrator, NULL, NULL), RES_BAD_ARG); + CHECK(smc_solve(dev, &integrator, NULL, NULL), RES_BAD_ARG); + CHECK(smc_solve(NULL, NULL, NULL, &estimator), RES_BAD_ARG); + CHECK(smc_solve(dev, NULL, NULL, &estimator), RES_BAD_ARG); + CHECK(smc_solve(NULL, &integrator, NULL, &estimator), RES_BAD_ARG); + CHECK(smc_solve(dev, &integrator, NULL, &estimator), RES_OK); CHECK(smc_estimator_get_status(NULL, NULL), RES_BAD_ARG); CHECK(smc_estimator_get_status(estimator, NULL), RES_BAD_ARG); @@ -100,7 +96,15 @@ main(int argc, char** argv) (log(2.0) - log(1.0), SMC_DOUBLE(status.E), SMC_DOUBLE(status.SE)), 1); CHECK(smc_estimator_ref_put(estimator), RES_OK); - CHECK(smc_solve(dev, cos_x, &smc_float, (void*)0xC0DE, &estimator), RES_OK); + integrator.type = NULL; + CHECK(smc_solve(dev, &integrator, NULL, &estimator), RES_BAD_ARG); + integrator.type = &smc_double; + integrator.integrand = NULL; + CHECK(smc_solve(dev, &integrator, NULL, &estimator), RES_BAD_ARG); + + integrator.integrand = cos_x; + integrator.type = &smc_float; + CHECK(smc_solve(dev, &integrator, (void*)0xC0DE, &estimator), RES_OK); CHECK(smc_estimator_get_status(estimator, &status), RES_OK); CHECK(eq_eps ((float)(sin(3.0*PI/4.0) - sin(PI/4.0)),