solstice-solver

Solver library of the solstice app
git clone git://git.meso-star.com/solstice-solver.git
Log | Files | Refs | README | LICENSE

commit 699d37378c627bb3bee8f15166c48d3eda962e2b
parent 59d25a3993bfb38026ba36da12efb88e098137b3
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 21 Sep 2017 11:35:14 +0200

Merge branch 'feature_bsdf_lifo_alloc' into develop

Diffstat:
Msrc/ssol_device.c | 23+++++++++++++++++++++--
Msrc/ssol_device_c.h | 1+
Msrc/ssol_draw_pt.c | 23++++++++---------------
Msrc/ssol_material.c | 98++++++++++++++++++++++++++++++++++---------------------------------------------
Msrc/ssol_material_c.h | 4++--
Msrc/ssol_solver.c | 35+++++++++++++----------------------
Msrc/test_ssol_by_receiver_integration.c | 12++++++++----
7 files changed, 95 insertions(+), 101 deletions(-)

diff --git a/src/ssol_device.c b/src/ssol_device.c @@ -49,6 +49,13 @@ device_release(ref_T* ref) ASSERT(ref); dev = CONTAINER_OF(ref, struct ssol_device, ref); darray_tile_release(&dev->tiles); + if(dev->bsdf_allocators) { + unsigned i; + FOR_EACH(i, 0, dev->nthreads) { + mem_shutdown_lifo_allocator(&dev->bsdf_allocators[i]); + } + MEM_RM(dev->allocator, dev->bsdf_allocators); + } if(dev->s3d) S3D(device_ref_put(dev->s3d)); if(dev->scpr_mesh) SCPR(mesh_ref_put(dev->scpr_mesh)); MEM_RM(dev->allocator, dev); @@ -67,6 +74,7 @@ ssol_device_create { struct ssol_device* dev = NULL; struct mem_allocator* allocator; + unsigned i; res_T res = RES_OK; if(nthreads_hint == 0 || !out_dev) { @@ -88,12 +96,23 @@ ssol_device_create dev->nthreads = MMIN(nthreads_hint, (unsigned)omp_get_num_procs()); omp_set_num_threads((int)dev->nthreads); + dev->bsdf_allocators = MEM_CALLOC + (dev->allocator, dev->nthreads, sizeof(struct mem_allocator)); + if(!dev->bsdf_allocators) { + res = RES_MEM_ERR; + goto error; + } + + FOR_EACH(i, 0, dev->nthreads) { + res = mem_init_lifo_allocator + (&dev->bsdf_allocators[i], dev->allocator, 4096); + if(res != RES_OK) goto error; + } + res = darray_tile_resize(&dev->tiles, dev->nthreads); if(res != RES_OK) goto error; - res = s3d_device_create(logger, mem_allocator, 0, &dev->s3d); if(res != RES_OK) goto error; - res = scpr_mesh_create(mem_allocator, &dev->scpr_mesh); if(res != RES_OK) goto error; diff --git a/src/ssol_device_c.h b/src/ssol_device_c.h @@ -39,6 +39,7 @@ struct s3d_device; struct ssol_device { struct logger* logger; struct mem_allocator* allocator; + struct mem_allocator* bsdf_allocators; /* Per thread allocator */ unsigned nthreads; int verbose; diff --git a/src/ssol_draw_pt.c b/src/ssol_draw_pt.c @@ -38,7 +38,6 @@ ******************************************************************************/ struct thread_context { struct ssp_rng* rng; - struct ssf_bsdf* bsdf; struct ranst_sun_wl* ran_wl; float up[3]; }; @@ -48,7 +47,6 @@ thread_context_release(struct thread_context* ctx) { ASSERT(ctx); if(ctx->rng) SSP(rng_ref_put(ctx->rng)); - if(ctx->bsdf) SSF(bsdf_ref_put(ctx->bsdf)); if(ctx->ran_wl) ranst_sun_wl_ref_put(ctx->ran_wl); } @@ -57,16 +55,10 @@ thread_context_init (struct mem_allocator* allocator, struct thread_context* ctx) { - res_T res = RES_OK; ASSERT(ctx); + (void)allocator; memset(ctx, 0, sizeof(ctx[0])); - res = ssf_bsdf_create(allocator, &ctx->bsdf); - if(res != RES_OK) goto error; -exit: - return res; -error: - thread_context_release(ctx); - goto exit; + return RES_OK; } static void @@ -143,6 +135,7 @@ Li(struct ssol_scene* scn, struct ray_data ray_data = RAY_DATA_NULL; struct ssol_instance* inst; struct ssol_material* mtl; + struct ssf_bsdf* bsdf = NULL; const struct shaded_shape* sshape; struct ssol_surface_fragment frag; size_t isshape; @@ -229,9 +222,8 @@ Li(struct ssol_scene* scn, /* Shaded normal may look backward the outgoing direction */ if(d3_dot(N, wo) > 0) break; - SSF(bsdf_clear(ctx->bsdf)); - res = material_setup_bsdf - (mtl, &frag, wl, &medium, 1/*Rendering*/, ctx->bsdf); + if(bsdf) SSF(bsdf_ref_put(bsdf)), bsdf = NULL; + res = material_create_bsdf(mtl, &frag, wl, &medium, 1/*Rendering*/, &bsdf); if(res != RES_OK) goto error; /* Update the ray */ @@ -248,11 +240,11 @@ Li(struct ssol_scene* scn, d3_minus(wo, wo); if(scn->sun) { L += throughput * sun_lighting - (scn->sun, view, &ray_data, ctx->bsdf, wo, N, ray_org); + (scn->sun, view, &ray_data, bsdf, wo, N, ray_org); } /* Sampling a bounce direction */ - R = ssf_bsdf_sample(ctx->bsdf, ctx->rng, wo, N, wi, &type, &pdf); + R = ssf_bsdf_sample(bsdf, ctx->rng, wo, N, wi, &type, &pdf); ASSERT(0 <= R && R <= 1); /* Due to the shading normal, the sampled direction may point in the wrong @@ -282,6 +274,7 @@ Li(struct ssol_scene* scn, d3_splat(val, L); exit: + if(bsdf) SSF(bsdf_ref_put(bsdf)); ssol_medium_clear(&medium); return res; error: diff --git a/src/ssol_material.c b/src/ssol_material.c @@ -32,6 +32,7 @@ #include <star/ssf.h> #include <math.h> +#include <omp.h> /******************************************************************************* * Helper functions @@ -78,15 +79,15 @@ shade_normal_default } static res_T -setup_dielectric_bsdf +create_dielectric_bsdf (const struct ssol_material* mtl, const struct ssol_surface_fragment* fragment, const double wavelength, /* In nanometer */ const struct ssol_medium* medium, - struct ssf_bsdf* bsdf) + struct ssf_bsdf** bsdf) { - struct ssf_bxdf* bxdf = NULL; double eta_i, eta_t; + const int ithread = omp_get_thread_num(); res_T res = RES_OK; ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_DIELECTRIC); ASSERT(medium && bsdf); @@ -101,33 +102,28 @@ setup_dielectric_bsdf eta_i = ssol_data_get_value(&mtl->out_medium.refractive_index, wavelength); eta_t = ssol_data_get_value(&mtl->in_medium.refractive_index, wavelength); - res = ssf_bxdf_create - (mtl->dev->allocator, &ssf_specular_dielectric_dielectric_interface, &bxdf); - if(res != RES_OK) goto error; - - res = ssf_specular_dielectric_dielectric_interface_setup - (bxdf, eta_i, eta_t); - if(res != RES_OK) goto error; - - res = ssf_bsdf_add(bsdf, bxdf, 1.0); - if(res != RES_OK) goto error; + #define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0 + CALL(ssf_bsdf_create(&mtl->dev->bsdf_allocators[ithread], + &ssf_specular_dielectric_dielectric_interface, bsdf)); + CALL(ssf_specular_dielectric_dielectric_interface_setup(*bsdf, eta_i, eta_t)); + #undef CALL exit: - if(bxdf) SSF(bxdf_ref_put(bxdf)); return res; error: + if(*bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL; goto exit; } static res_T -setup_matte_bsdf +create_matte_bsdf (const struct ssol_material* mtl, const struct ssol_surface_fragment* fragment, const double wavelength, /* In nanometer */ - struct ssf_bsdf* bsdf) + struct ssf_bsdf** bsdf) { - struct ssf_bxdf* brdf = NULL; double reflectivity; + const int ithread = omp_get_thread_num(); res_T res; ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_MATTE); ASSERT(bsdf); @@ -137,35 +133,32 @@ setup_matte_bsdf (mtl->dev, mtl->buf, wavelength, fragment, &reflectivity); /* Setup the BRDF */ - res = ssf_bxdf_create(mtl->dev->allocator, &ssf_lambertian_reflection, &brdf); + res = ssf_bsdf_create + (&mtl->dev->bsdf_allocators[ithread], &ssf_lambertian_reflection, bsdf); if(res != RES_OK) goto error; - res = ssf_lambertian_reflection_setup(brdf, reflectivity); - if(res != RES_OK) goto error; - - /* Setup the BSDF */ - res = ssf_bsdf_add(bsdf, brdf, 1.0); + res = ssf_lambertian_reflection_setup(*bsdf, reflectivity); if(res != RES_OK) goto error; exit: - if(brdf) SSF(bxdf_ref_put(brdf)); return res; error: + if(*bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL; goto exit; } static res_T -setup_mirror_bsdf +create_mirror_bsdf (const struct ssol_material* mtl, const struct ssol_surface_fragment* fragment, const double wavelength, /* In nanometer */ const int rendering, - struct ssf_bsdf* bsdf) + struct ssf_bsdf** bsdf) { - struct ssf_bxdf* brdf = NULL; struct ssf_fresnel* fresnel = NULL; struct ssf_microfacet_distribution* distrib = NULL; double roughness; double reflectivity; + const int ithread = omp_get_thread_num(); res_T res; ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_MIRROR); ASSERT(bsdf); @@ -184,9 +177,10 @@ setup_mirror_bsdf /* Setup the BRDF */ if(roughness == 0) { /* Purely specular reflection */ - res = ssf_bxdf_create(mtl->dev->allocator, &ssf_specular_reflection, &brdf); + res = ssf_bsdf_create + (&mtl->dev->bsdf_allocators[ithread], &ssf_specular_reflection, bsdf); if(res != RES_OK) goto error; - res = ssf_specular_reflection_setup(brdf, fresnel); + res = ssf_specular_reflection_setup(*bsdf, fresnel); if(res != RES_OK) goto error; } else { /* Glossy reflection */ res = ssf_microfacet_distribution_create @@ -199,42 +193,38 @@ setup_mirror_bsdf * evaluated and consequently it returns an invalid result for direct * lighting. */ if(rendering) { - res = ssf_bxdf_create - (mtl->dev->allocator, &ssf_microfacet_reflection, &brdf); + res = ssf_bsdf_create + (&mtl->dev->bsdf_allocators[ithread], &ssf_microfacet_reflection, bsdf); } else { - res = ssf_bxdf_create - (mtl->dev->allocator, &ssf_microfacet2_reflection, &brdf); + res = ssf_bsdf_create + (&mtl->dev->bsdf_allocators[ithread], &ssf_microfacet2_reflection, bsdf); } if(res != RES_OK) goto error; - res = ssf_microfacet_reflection_setup(brdf, fresnel, distrib); + res = ssf_microfacet_reflection_setup(*bsdf, fresnel, distrib); if(res != RES_OK) goto error; } - /* Setup the BSDF */ - res = ssf_bsdf_add(bsdf, brdf, 1.0); - if(res != RES_OK) goto error; - exit: - if(brdf) SSF(bxdf_ref_put(brdf)); if(fresnel) SSF(fresnel_ref_put(fresnel)); if(distrib) SSF(microfacet_distribution_ref_put(distrib)); return res; error: + if(*bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL; goto exit; } static res_T -setup_thin_dielectric_bsdf +create_thin_dielectric_bsdf (const struct ssol_material* mtl, const struct ssol_surface_fragment* fragment, const double wavelength, /* In nanometer */ - struct ssf_bsdf* bsdf) + struct ssf_bsdf** bsdf) { - struct ssf_bxdf* bxdf = NULL; double thickness; double absorption; double eta_i; double eta_t; + const int ithread = omp_get_thread_num(); res_T res = RES_OK; ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_THIN_DIELECTRIC); ASSERT(bsdf); @@ -248,21 +238,17 @@ setup_thin_dielectric_bsdf thickness = mtl->data.thin_dielectric.thickness; /* Setup the BxDF */ - res = ssf_bxdf_create - (mtl->dev->allocator, &ssf_thin_specular_dielectric, &bxdf); + res = ssf_bsdf_create + (&mtl->dev->bsdf_allocators[ithread], &ssf_thin_specular_dielectric, bsdf); if(res != RES_OK) goto error; res = ssf_thin_specular_dielectric_setup - (bxdf, absorption, eta_i, eta_t, thickness); - if(res != RES_OK) goto error; - - /* Setup the BSDF */ - res = ssf_bsdf_add(bsdf, bxdf, 1.0); + (*bsdf, absorption, eta_i, eta_t, thickness); if(res != RES_OK) goto error; exit: - if(bxdf) SSF(bxdf_ref_put(bxdf)); return res; error: + if(*bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL; goto exit; } @@ -661,30 +647,30 @@ material_shade_normal } res_T -material_setup_bsdf +material_create_bsdf (const struct ssol_material* mtl, const struct ssol_surface_fragment* fragment, const double wavelength, /* In nanometer */ const struct ssol_medium* medium, const int rendering, /* Is BSDF used for rendering */ - struct ssf_bsdf* bsdf) + struct ssf_bsdf** bsdf) { res_T res = RES_OK; ASSERT(mtl); switch(mtl->type) { case SSOL_MATERIAL_DIELECTRIC: - res = setup_dielectric_bsdf + res = create_dielectric_bsdf (mtl, fragment, wavelength, medium, bsdf); break; case SSOL_MATERIAL_MATTE: - res = setup_matte_bsdf(mtl, fragment, wavelength, bsdf); + res = create_matte_bsdf(mtl, fragment, wavelength, bsdf); break; case SSOL_MATERIAL_MIRROR: - res = setup_mirror_bsdf(mtl, fragment, wavelength, rendering, bsdf); + res = create_mirror_bsdf(mtl, fragment, wavelength, rendering, bsdf); break; case SSOL_MATERIAL_THIN_DIELECTRIC: - res = setup_thin_dielectric_bsdf(mtl, fragment, wavelength, bsdf); + res = create_thin_dielectric_bsdf(mtl, fragment, wavelength, bsdf); break; case SSOL_MATERIAL_VIRTUAL: /* Nothing to shade */ break; default: FATAL("Unreachable code\n"); break; diff --git a/src/ssol_material_c.h b/src/ssol_material_c.h @@ -78,13 +78,13 @@ material_shade_normal double N[3]); extern LOCAL_SYM res_T -material_setup_bsdf +material_create_bsdf (const struct ssol_material* mtl, const struct ssol_surface_fragment* fragment, const double wavelength, /* In nanometer */ const struct ssol_medium* medium, /* Current medium */ const int rendering, /* Is material used for rendering purposes */ - struct ssf_bsdf* bsdf); /* Bidirectional Scattering Distribution Function */ + struct ssf_bsdf** bsdf); /* Bidirectional Scattering Distribution Function */ extern LOCAL_SYM res_T material_get_next_medium diff --git a/src/ssol_solver.c b/src/ssol_solver.c @@ -51,7 +51,6 @@ ******************************************************************************/ struct thread_context { struct ssp_rng* rng; - struct ssf_bsdf* bsdf; struct mc_data cos_factor; struct mc_data absorbed_by_receivers; struct mc_data shadowed; @@ -69,7 +68,6 @@ thread_context_release(struct thread_context* ctx) { ASSERT(ctx); if(ctx->rng) SSP(rng_ref_put(ctx->rng)); - if(ctx->bsdf) SSF(bsdf_ref_put(ctx->bsdf)); htable_receiver_release(&ctx->mc_rcvs); htable_sampled_release(&ctx->mc_samps); darray_path_release(&ctx->paths); @@ -78,22 +76,12 @@ thread_context_release(struct thread_context* ctx) static res_T thread_context_init(struct mem_allocator* allocator, struct thread_context* ctx) { - res_T res = RES_OK; ASSERT(ctx); - memset(ctx, 0, sizeof(ctx[0])); htable_receiver_init(allocator, &ctx->mc_rcvs); htable_sampled_init(allocator, &ctx->mc_samps); darray_path_init(allocator, &ctx->paths); - - res = ssf_bsdf_create(allocator, &ctx->bsdf); - if(res != RES_OK) goto error; - -exit: - return res; -error: - thread_context_release(ctx); - goto exit; + return RES_OK; } /* Define a copy functor only for consistency since this function will not be @@ -105,7 +93,6 @@ thread_context_copy res_T res = RES_OK; ASSERT(dst && src); dst->rng = src->rng; - dst->bsdf = src->bsdf; dst->cos_factor = src->cos_factor; dst->absorbed_by_receivers = src->absorbed_by_receivers; dst->shadowed = src->shadowed; @@ -428,7 +415,6 @@ point_is_receiver(const struct point* pt) static FINLINE res_T point_shade (struct point* pt, - struct ssf_bsdf* bsdf, const struct ssol_medium* in_medium, struct ssol_medium* out_medium, struct ssp_rng* rng, @@ -436,11 +422,12 @@ point_shade { struct ssol_material* mtl; struct ssol_surface_fragment frag; + struct ssf_bsdf* bsdf = NULL; double propagated = 0; double wi[3], N[3], pdf; int type = 0; res_T res; - ASSERT(pt && bsdf && in_medium && out_medium && rng && dir); + ASSERT(pt && in_medium && out_medium && rng && dir); /* TODO ensure that if `prim' was sampled, then the surface fragment setup * remains valid in *all* situations, i.e. even though the point primitive @@ -457,9 +444,9 @@ point_shade /* Shade the surface fragment */ mtl = point_get_material(pt); - SSF(bsdf_clear(bsdf)); - res = material_setup_bsdf(mtl, &frag, pt->wl, in_medium, 0, bsdf); - if(res != RES_OK) return res; + + res = material_create_bsdf(mtl, &frag, pt->wl, in_medium, 0, &bsdf); + if(res != RES_OK) goto error; /* Perturbe the normal */ material_shade_normal(mtl, &frag, pt->wl, N); @@ -494,7 +481,12 @@ point_shade } else { ssol_medium_copy(out_medium, in_medium); } - return RES_OK; + +exit: + if(bsdf) SSF(bsdf_ref_put(bsdf)); + return res; +error: + goto exit; } static FINLINE void @@ -930,8 +922,7 @@ trace_radiative_path } else { /* Modulate the point weights wrt its scattering functions and generate * an outgoing direction and set out_medium accordingly */ - res = point_shade(&pt, thread_ctx->bsdf, &in_medium, &out_medium, - thread_ctx->rng, pt.dir); + res = point_shade(&pt, &in_medium, &out_medium, thread_ctx->rng, pt.dir); if(res != RES_OK) goto error; } diff --git a/src/test_ssol_by_receiver_integration.c b/src/test_ssol_by_receiver_integration.c @@ -139,22 +139,26 @@ main(int argc, char** argv) printf("Ir(target) = %g +/- %g\n", mc_rcv.incoming_flux.E, mc_rcv.incoming_flux.SE); CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT, 0), RES_OK); - CHECK(eq_eps(mc_rcv.incoming_flux.E, S_DNI_cos, S_DNI_cos * 2e-1), 1); + CHECK(eq_eps + (mc_rcv.incoming_flux.E, S_DNI_cos, + mc_rcv.incoming_flux.SE*3), 1); CHECK(ssol_solve(scene, rng, 8 * N__, NULL, &estimator2), RES_OK); CHECK(GET_MC_RCV(estimator2, target, SSOL_FRONT, &mc_rcv), RES_OK); printf("Ir(target) = %g +/- %g\n", mc_rcv.incoming_flux.E, mc_rcv.incoming_flux.SE); - CHECK(eq_eps(mc_rcv.incoming_flux.E, S_DNI_cos, S_DNI_cos * 5e-2), 1); + CHECK(eq_eps(mc_rcv.incoming_flux.E, S_DNI_cos, mc_rcv.incoming_flux.SE*3), 1); CHECK(ssol_estimator_ref_put(estimator1), RES_OK); CHECK(ssol_solve(scene, rng, 3 * N__, NULL, &estimator1), RES_OK); CHECK(GET_MC_RCV(estimator1, target, SSOL_FRONT, &mc_rcv), RES_OK); printf("Ir(target) = %g +/- %g\n", mc_rcv.incoming_flux.E, mc_rcv.incoming_flux.SE); - CHECK(eq_eps(mc_rcv.incoming_flux.E, S_DNI_cos, S_DNI_cos * 1e-1), 1); + CHECK(eq_eps + (mc_rcv.incoming_flux.E, S_DNI_cos, + mc_rcv.incoming_flux.SE*3), 1); CHECK(GET_MC_SAMP_X_RCV(estimator1, heliostat, target, SSOL_FRONT, &mc_rcv), RES_OK); printf("Ir(heliostat=>target) = %g +/- %g\n", mc_rcv.incoming_flux.E, mc_rcv.incoming_flux.SE); - CHECK(eq_eps(mc_rcv.incoming_flux.E, S_DNI_cos, S_DNI_cos * 1e-1), 1); + CHECK(eq_eps(mc_rcv.incoming_flux.E, S_DNI_cos, mc_rcv.incoming_flux.SE*3), 1); /* Free data */ CHECK(ssol_instance_ref_put(heliostat), RES_OK);