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:
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);