Cycles: optimization for constant background colors.

Skip shader evaluation then, as we already do for lights. Less than
1% faster in my tests, but might as well be consistent for both.
This commit is contained in:
Brecht Van Lommel 2019-02-19 17:44:58 +01:00
parent 9c7517fb63
commit 7778a1a0a1
4 changed files with 135 additions and 95 deletions

@ -351,7 +351,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
out = make_float3(roughness, roughness, roughness); out = make_float3(roughness, roughness, roughness);
} }
else { else {
out = shader_emissive_eval(kg, &sd); out = shader_emissive_eval(&sd);
} }
break; break;
} }
@ -475,8 +475,9 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
shader_setup_from_background(kg, &sd, &ray); shader_setup_from_background(kg, &sd, &ray);
/* evaluate */ /* evaluate */
int flag = 0; /* we can't know which type of BSDF this is for */ int path_flag = 0; /* we can't know which type of BSDF this is for */
out = shader_eval_background(kg, &sd, &state, flag); shader_eval_surface(kg, &sd, &state, path_flag | PATH_RAY_EMISSION);
out = shader_background_eval(&sd);
break; break;
} }
default: default:
@ -554,8 +555,9 @@ ccl_device void kernel_background_evaluate(KernelGlobals *kg,
shader_setup_from_background(kg, &sd, &ray); shader_setup_from_background(kg, &sd, &ray);
/* evaluate */ /* evaluate */
int flag = 0; /* we can't know which type of BSDF this is for */ int path_flag = 0; /* we can't know which type of BSDF this is for */
float3 color = shader_eval_background(kg, &sd, &state, flag); shader_eval_surface(kg, &sd, &state, path_flag | PATH_RAY_EMISSION);
float3 color = shader_background_eval(&sd);
/* write output */ /* write output */
output[i] += make_float4(color.x, color.y, color.z, 0.0f); output[i] += make_float4(color.x, color.y, color.z, 0.0f);

@ -29,43 +29,36 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
/* setup shading at emitter */ /* setup shading at emitter */
float3 eval; float3 eval;
int shader_flag = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).flags; if(shader_constant_emission_eval(kg, ls->shader, &eval)) {
#ifdef __BACKGROUND_MIS__
if(ls->type == LIGHT_BACKGROUND) {
Ray ray;
ray.D = ls->D;
ray.P = ls->P;
ray.t = 1.0f;
ray.time = time;
ray.dP = differential3_zero();
ray.dD = dI;
shader_setup_from_background(kg, emission_sd, &ray);
path_state_modify_bounce(state, true);
eval = shader_eval_background(kg, emission_sd, state, 0);
path_state_modify_bounce(state, false);
}
else
#endif
if(shader_flag & SD_HAS_CONSTANT_EMISSION)
{
eval.x = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[0];
eval.y = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[1];
eval.z = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[2];
if((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) { if((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) {
ls->Ng = -ls->Ng; ls->Ng = -ls->Ng;
} }
} }
else else {
{ /* Setup shader data and call shader_eval_surface once, better
shader_setup_from_sample(kg, emission_sd, * for GPU coherence and compile times. */
ls->P, ls->Ng, I, #ifdef __BACKGROUND_MIS__
ls->shader, ls->object, ls->prim, if(ls->type == LIGHT_BACKGROUND) {
ls->u, ls->v, t, time, false, ls->lamp); Ray ray;
ray.D = ls->D;
ray.P = ls->P;
ray.t = 1.0f;
ray.time = time;
ray.dP = differential3_zero();
ray.dD = dI;
ls->Ng = emission_sd->Ng; shader_setup_from_background(kg, emission_sd, &ray);
}
else
#endif
{
shader_setup_from_sample(kg, emission_sd,
ls->P, ls->Ng, I,
ls->shader, ls->object, ls->prim,
ls->u, ls->v, t, time, false, ls->lamp);
ls->Ng = emission_sd->Ng;
}
/* No proper path flag, we're evaluating this for all closures. that's /* No proper path flag, we're evaluating this for all closures. that's
* weak but we'd have to do multiple evaluations otherwise. */ * weak but we'd have to do multiple evaluations otherwise. */
@ -73,8 +66,16 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
shader_eval_surface(kg, emission_sd, state, PATH_RAY_EMISSION); shader_eval_surface(kg, emission_sd, state, PATH_RAY_EMISSION);
path_state_modify_bounce(state, false); path_state_modify_bounce(state, false);
/* Evaluate emissive closure. */ /* Evaluate closures. */
eval = shader_emissive_eval(kg, emission_sd); #ifdef __BACKGROUND_MIS__
if (ls->type == LIGHT_BACKGROUND) {
eval = shader_background_eval(emission_sd);
}
else
#endif
{
eval = shader_emissive_eval(emission_sd);
}
} }
eval *= ls->eval_fac; eval *= ls->eval_fac;
@ -201,7 +202,7 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg,
ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf) ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf)
{ {
/* evaluate emissive closure */ /* evaluate emissive closure */
float3 L = shader_emissive_eval(kg, sd); float3 L = shader_emissive_eval(sd);
#ifdef __HAIR__ #ifdef __HAIR__
if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) && (sd->type & PRIMITIVE_ALL_TRIANGLE)) if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) && (sd->type & PRIMITIVE_ALL_TRIANGLE))
@ -294,7 +295,7 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
#ifdef __BACKGROUND__ #ifdef __BACKGROUND__
int shader = kernel_data.background.surface_shader; int shader = kernel_data.background.surface_shader;
/* use visibility flag to skip lights */ /* Use visibility flag to skip lights. */
if(shader & SHADER_EXCLUDE_ANY) { if(shader & SHADER_EXCLUDE_ANY) {
if(((shader & SHADER_EXCLUDE_DIFFUSE) && (state->flag & PATH_RAY_DIFFUSE)) || if(((shader & SHADER_EXCLUDE_DIFFUSE) && (state->flag & PATH_RAY_DIFFUSE)) ||
((shader & SHADER_EXCLUDE_GLOSSY) && ((shader & SHADER_EXCLUDE_GLOSSY) &&
@ -305,20 +306,27 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
return make_float3(0.0f, 0.0f, 0.0f); return make_float3(0.0f, 0.0f, 0.0f);
} }
/* evaluate background closure */
/* Evaluate background shader. */
float3 L;
if(!shader_constant_emission_eval(kg, shader, &L)) {
# ifdef __SPLIT_KERNEL__ # ifdef __SPLIT_KERNEL__
Ray priv_ray = *ray; Ray priv_ray = *ray;
shader_setup_from_background(kg, emission_sd, &priv_ray); shader_setup_from_background(kg, emission_sd, &priv_ray);
# else # else
shader_setup_from_background(kg, emission_sd, ray); shader_setup_from_background(kg, emission_sd, ray);
# endif # endif
path_state_modify_bounce(state, true); path_state_modify_bounce(state, true);
float3 L = shader_eval_background(kg, emission_sd, state, state->flag); shader_eval_surface(kg, emission_sd, state, PATH_RAY_EMISSION);
path_state_modify_bounce(state, false); path_state_modify_bounce(state, false);
L = shader_background_eval(emission_sd);
}
/* Background MIS weights. */
#ifdef __BACKGROUND_MIS__ #ifdef __BACKGROUND_MIS__
/* check if background light exists or if we should skip pdf */ /* Check if background light exists or if we should skip pdf. */
int res_x = kernel_data.integrator.pdf_background_res_x; int res_x = kernel_data.integrator.pdf_background_res_x;
if(!(state->flag & PATH_RAY_MIS_SKIP) && res_x) { if(!(state->flag & PATH_RAY_MIS_SKIP) && res_x) {

@ -984,9 +984,40 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b
} }
#endif /* __SUBSURFACE__ */ #endif /* __SUBSURFACE__ */
/* Constant emission optimization */
ccl_device bool shader_constant_emission_eval(KernelGlobals *kg, int shader, float3 *eval)
{
int shader_index = shader & SHADER_MASK;
int shader_flag = kernel_tex_fetch(__shaders, shader_index).flags;
if (shader_flag & SD_HAS_CONSTANT_EMISSION) {
*eval = make_float3(
kernel_tex_fetch(__shaders, shader_index).constant_emission[0],
kernel_tex_fetch(__shaders, shader_index).constant_emission[1],
kernel_tex_fetch(__shaders, shader_index).constant_emission[2]);
return true;
}
return false;
}
/* Background */
ccl_device float3 shader_background_eval(ShaderData *sd)
{
if(sd->flag & SD_EMISSION) {
return sd->closure_emission_background;
}
else {
return make_float3(0.0f, 0.0f, 0.0f);
}
}
/* Emission */ /* Emission */
ccl_device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd) ccl_device float3 shader_emissive_eval(ShaderData *sd)
{ {
if(sd->flag & SD_EMISSION) { if(sd->flag & SD_EMISSION) {
return emissive_simple_eval(sd->Ng, sd->I) * sd->closure_emission_background; return emissive_simple_eval(sd->Ng, sd->I) * sd->closure_emission_background;
@ -1034,20 +1065,32 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
sd->num_closure_left = max_closures; sd->num_closure_left = max_closures;
#ifdef __OSL__ #ifdef __OSL__
if(kg->osl) if(kg->osl) {
OSLShader::eval_surface(kg, sd, state, path_flag); if (sd->object == OBJECT_NONE) {
OSLShader::eval_background(kg, sd, state, path_flag);
}
else {
OSLShader::eval_surface(kg, sd, state, path_flag);
}
}
else else
#endif #endif
{ {
#ifdef __SVM__ #ifdef __SVM__
svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag); svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
#else #else
DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, if(sd->object == OBJECT_NONE) {
sizeof(DiffuseBsdf), sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f);
make_float3(0.8f, 0.8f, 0.8f)); sd->flag |= SD_EMISSION;
if(bsdf != NULL) { }
bsdf->N = sd->N; else {
sd->flag |= bsdf_diffuse_setup(bsdf); DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd,
sizeof(DiffuseBsdf),
make_float3(0.8f, 0.8f, 0.8f));
if(bsdf != NULL) {
bsdf->N = sd->N;
sd->flag |= bsdf_diffuse_setup(bsdf);
}
} }
#endif #endif
} }
@ -1057,36 +1100,6 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
} }
} }
/* Background Evaluation */
ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd,
ccl_addr_space PathState *state, int path_flag)
{
sd->num_closure = 0;
sd->num_closure_left = 0;
#ifdef __SVM__
# ifdef __OSL__
if(kg->osl) {
OSLShader::eval_background(kg, sd, state, path_flag);
}
else
# endif /* __OSL__ */
{
svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
}
if(sd->flag & SD_EMISSION) {
return sd->closure_emission_background;
}
else {
return make_float3(0.0f, 0.0f, 0.0f);
}
#else /* __SVM__ */
return make_float3(0.8f, 0.8f, 0.8f);
#endif /* __SVM__ */
}
/* Volume */ /* Volume */
#ifdef __VOLUME__ #ifdef __VOLUME__

@ -219,21 +219,38 @@ bool Shader::is_constant_emission(float3 *emission)
{ {
ShaderInput *surf = graph->output()->input("Surface"); ShaderInput *surf = graph->output()->input("Surface");
if(!surf->link || surf->link->parent->type != EmissionNode::node_type) { if(surf->link == NULL) {
return false; return false;
} }
EmissionNode *node = (EmissionNode*) surf->link->parent; if(surf->link->parent->type == EmissionNode::node_type) {
EmissionNode *node = (EmissionNode*) surf->link->parent;
assert(node->input("Color")); assert(node->input("Color"));
assert(node->input("Strength")); assert(node->input("Strength"));
if(node->input("Color")->link || node->input("Strength")->link) { if(node->input("Color")->link || node->input("Strength")->link) {
return false;
}
*emission = node->color*node->strength;
}
else if(surf->link->parent->type == BackgroundNode::node_type) {
BackgroundNode *node = (BackgroundNode*) surf->link->parent;
assert(node->input("Color"));
assert(node->input("Strength"));
if(node->input("Color")->link || node->input("Strength")->link) {
return false;
}
*emission = node->color*node->strength;
}
else {
return false; return false;
} }
*emission = node->color*node->strength;
return true; return true;
} }