commit 8b7d952dda10c81f5ff50db0828e5b499848f92f
parent ec19567c234437e145aa5c18fe54cc35b6aca76c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 5 Sep 2017 15:41:21 +0200
Use a per thread LIFO allocator to create the material BSDFs
This drastically improves the integration performances by reducing the
thread concurrency on the ssol_device allocator during the BSDF creation.
Diffstat:
4 files changed, 53 insertions(+), 17 deletions(-)
diff --git a/src/ssol_device.c b/src/ssol_device.c
@@ -18,6 +18,7 @@
#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
+#include <rsys/mem_lifo_allocator.h>
#include <star/s3d.h>
#include <star/scpr.h>
@@ -49,6 +50,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 +75,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 +97,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_material.c b/src/ssol_material.c
@@ -32,6 +32,7 @@
#include <star/ssf.h>
#include <math.h>
+#include <omp.h>
/*******************************************************************************
* Helper functions
@@ -96,6 +97,7 @@ create_dielectric_bsdf
struct ssf_bsdf** bsdf)
{
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);
@@ -111,15 +113,15 @@ create_dielectric_bsdf
eta_t = ssol_data_get_value(&mtl->in_medium.refractive_index, wavelength);
#define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0
- CALL(ssf_bsdf_create
- (mtl->dev->allocator, &ssf_specular_dielectric_dielectric_interface, bsdf));
+ 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:
return res;
error:
- if(bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL;
+ if(*bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL;
goto exit;
}
@@ -131,6 +133,7 @@ create_matte_bsdf
struct ssf_bsdf** bsdf)
{
double reflectivity;
+ const int ithread = omp_get_thread_num();
res_T res;
ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_MATTE);
ASSERT(bsdf);
@@ -140,7 +143,8 @@ create_matte_bsdf
(mtl->dev, mtl->buf, wavelength, fragment, &reflectivity);
/* Setup the BRDF */
- res = ssf_bsdf_create(mtl->dev->allocator, &ssf_lambertian_reflection, bsdf);
+ res = ssf_bsdf_create
+ (&mtl->dev->bsdf_allocators[ithread], &ssf_lambertian_reflection, bsdf);
if(res != RES_OK) goto error;
res = ssf_lambertian_reflection_setup(*bsdf, reflectivity);
if(res != RES_OK) goto error;
@@ -148,7 +152,7 @@ create_matte_bsdf
exit:
return res;
error:
- if(bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL;
+ if(*bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL;
goto exit;
}
@@ -164,6 +168,7 @@ create_mirror_bsdf
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);
@@ -182,7 +187,8 @@ create_mirror_bsdf
/* Setup the BRDF */
if(roughness == 0) { /* Purely specular reflection */
- res = ssf_bsdf_create(mtl->dev->allocator, &ssf_specular_reflection, bsdf);
+ res = ssf_bsdf_create
+ (&mtl->dev->bsdf_allocators[ithread], &ssf_specular_reflection, bsdf);
if(res != RES_OK) goto error;
res = ssf_specular_reflection_setup(*bsdf, fresnel);
if(res != RES_OK) goto error;
@@ -198,10 +204,10 @@ create_mirror_bsdf
* lighting. */
if(rendering) {
res = ssf_bsdf_create
- (mtl->dev->allocator, &ssf_microfacet_reflection, bsdf);
+ (&mtl->dev->bsdf_allocators[ithread], &ssf_microfacet_reflection, bsdf);
} else {
res = ssf_bsdf_create
- (mtl->dev->allocator, &ssf_microfacet2_reflection, bsdf);
+ (&mtl->dev->bsdf_allocators[ithread], &ssf_microfacet2_reflection, bsdf);
}
if(res != RES_OK) goto error;
res = ssf_microfacet_reflection_setup(*bsdf, fresnel, distrib);
@@ -213,7 +219,7 @@ exit:
if(distrib) SSF(microfacet_distribution_ref_put(distrib));
return res;
error:
- if(bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL;
+ if(*bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL;
goto exit;
}
@@ -228,6 +234,7 @@ create_thin_dielectric_bsdf
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);
@@ -242,7 +249,7 @@ create_thin_dielectric_bsdf
/* Setup the BxDF */
res = ssf_bsdf_create
- (mtl->dev->allocator, &ssf_thin_specular_dielectric, bsdf);
+ (&mtl->dev->bsdf_allocators[ithread], &ssf_thin_specular_dielectric, bsdf);
if(res != RES_OK) goto error;
res = ssf_thin_specular_dielectric_setup
(*bsdf, absorption, eta_i, eta_t, thickness);
@@ -251,7 +258,7 @@ create_thin_dielectric_bsdf
exit:
return res;
error:
- if(bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL;
+ if(*bsdf) SSF(bsdf_ref_put(*bsdf)), bsdf = NULL;
goto exit;
}
diff --git a/src/test_ssol_by_receiver_integration.c b/src/test_ssol_by_receiver_integration.c
@@ -139,22 +139,30 @@ main(int argc, char** argv)
printf("Ir(target) = %g +/- %g\n",
mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT, 0), RES_OK);
- CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S_DNI_cos, S_DNI_cos * 2e-1), 1);
+ CHECK(eq_eps
+ (mc_rcv.integrated_irradiance.E, S_DNI_cos,
+ mc_rcv.integrated_irradiance.SE*3), 1);
CHECK(ssol_solve(scene, rng, 8 * N__, 0, NULL, &estimator2), RES_OK);
CHECK(GET_MC_RCV(estimator2, target, SSOL_FRONT, &mc_rcv), RES_OK);
printf("Ir(target) = %g +/- %g\n",
mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
- CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S_DNI_cos, S_DNI_cos * 5e-2), 1);
+ CHECK(eq_eps
+ (mc_rcv.integrated_irradiance.E, S_DNI_cos,
+ mc_rcv.integrated_irradiance.SE*3), 1);
CHECK(ssol_estimator_ref_put(estimator1), RES_OK);
CHECK(ssol_solve(scene, rng, 3 * N__, 0, NULL, &estimator1), RES_OK);
CHECK(GET_MC_RCV(estimator1, target, SSOL_FRONT, &mc_rcv), RES_OK);
printf("Ir(target) = %g +/- %g\n",
mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
- CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S_DNI_cos, S_DNI_cos * 1e-1), 1);
+ CHECK(eq_eps
+ (mc_rcv.integrated_irradiance.E, S_DNI_cos,
+ mc_rcv.integrated_irradiance.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.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
- CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S_DNI_cos, S_DNI_cos * 1e-1), 1);
+ CHECK(eq_eps
+ (mc_rcv.integrated_irradiance.E, S_DNI_cos,
+ mc_rcv.integrated_irradiance.SE*3), 1);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat), RES_OK);