Cycles: optimization for constant background colors.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Tue, 19 Feb 2019 16:44:58 +0000 (17:44 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 17 Mar 2019 11:01:19 +0000 (12:01 +0100)
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.

intern/cycles/kernel/kernel_bake.h
intern/cycles/kernel/kernel_emission.h
intern/cycles/kernel/kernel_shader.h
intern/cycles/render/shader.cpp

index 920b100..37c163f 100644 (file)
@@ -351,7 +351,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
                                out = make_float3(roughness, roughness, roughness);
                        }
                        else {
-                               out = shader_emissive_eval(kg, &sd);
+                               out = shader_emissive_eval(&sd);
                        }
                        break;
                }
@@ -475,8 +475,9 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
                        shader_setup_from_background(kg, &sd, &ray);
 
                        /* evaluate */
-                       int flag = 0; /* we can't know which type of BSDF this is for */
-                       out = shader_eval_background(kg, &sd, &state, flag);
+                       int path_flag = 0; /* we can't know which type of BSDF this is for */
+                       shader_eval_surface(kg, &sd, &state, path_flag | PATH_RAY_EMISSION);
+                       out = shader_background_eval(&sd);
                        break;
                }
                default:
@@ -554,8 +555,9 @@ ccl_device void kernel_background_evaluate(KernelGlobals *kg,
        shader_setup_from_background(kg, &sd, &ray);
 
        /* evaluate */
-       int flag = 0; /* we can't know which type of BSDF this is for */
-       float3 color = shader_eval_background(kg, &sd, &state, flag);
+       int path_flag = 0; /* we can't know which type of BSDF this is for */
+       shader_eval_surface(kg, &sd, &state, path_flag | PATH_RAY_EMISSION);
+       float3 color = shader_background_eval(&sd);
 
        /* write output */
        output[i] += make_float4(color.x, color.y, color.z, 0.0f);
index 302bb04..9c47d1c 100644 (file)
@@ -29,43 +29,36 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
        /* setup shading at emitter */
        float3 eval;
 
-       int shader_flag = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).flags;
-
-#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(shader_constant_emission_eval(kg, ls->shader, &eval)) {
                if((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) {
                        ls->Ng = -ls->Ng;
                }
        }
-       else
-       {
-               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);
+       else {
+               /* Setup shader data and call shader_eval_surface once, better
+                * for GPU coherence and compile times. */
+#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);
+               }
+               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;
+                       ls->Ng = emission_sd->Ng;
+               }
 
                /* No proper path flag, we're evaluating this for all closures. that's
                 * 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);
                path_state_modify_bounce(state, false);
 
-               /* Evaluate emissive closure. */
-               eval = shader_emissive_eval(kg, emission_sd);
+               /* Evaluate closures. */
+#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;
@@ -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)
 {
        /* evaluate emissive closure */
-       float3 L = shader_emissive_eval(kg, sd);
+       float3 L = shader_emissive_eval(sd);
 
 #ifdef __HAIR__
        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__
        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_DIFFUSE) && (state->flag & PATH_RAY_DIFFUSE)) ||
                   ((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);
        }
 
-       /* evaluate background closure */
+
+       /* Evaluate background shader. */
+       float3 L;
+       if(!shader_constant_emission_eval(kg, shader, &L)) {
 #  ifdef __SPLIT_KERNEL__
-       Ray priv_ray = *ray;
-       shader_setup_from_background(kg, emission_sd, &priv_ray);
+               Ray priv_ray = *ray;
+               shader_setup_from_background(kg, emission_sd, &priv_ray);
 #  else
-       shader_setup_from_background(kg, emission_sd, ray);
+               shader_setup_from_background(kg, emission_sd, ray);
 #  endif
 
-       path_state_modify_bounce(state, true);
-       float3 L = shader_eval_background(kg, emission_sd, state, state->flag);
-       path_state_modify_bounce(state, false);
+               path_state_modify_bounce(state, true);
+               shader_eval_surface(kg, emission_sd, state, PATH_RAY_EMISSION);
+               path_state_modify_bounce(state, false);
+
+               L = shader_background_eval(emission_sd);
+       }
 
+       /* Background MIS weights. */
 #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;
 
        if(!(state->flag & PATH_RAY_MIS_SKIP) && res_x) {
index afb9ff1..eff792e 100644 (file)
@@ -984,9 +984,40 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b
 }
 #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 */
 
-ccl_device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
+ccl_device float3 shader_emissive_eval(ShaderData *sd)
 {
        if(sd->flag & SD_EMISSION) {
                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;
 
 #ifdef __OSL__
-       if(kg->osl)
-               OSLShader::eval_surface(kg, sd, state, path_flag);
+       if(kg->osl) {
+               if (sd->object == OBJECT_NONE) {
+                       OSLShader::eval_background(kg, sd, state, path_flag);
+               }
+               else {
+                       OSLShader::eval_surface(kg, sd, state, path_flag);
+               }
+       }
        else
 #endif
        {
 #ifdef __SVM__
                svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
 #else
-               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);
+               if(sd->object == OBJECT_NONE) {
+                       sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f);
+                       sd->flag |= SD_EMISSION;
+               }
+               else {
+                       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
        }
@@ -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 */
 
 #ifdef __VOLUME__
index 9f256a6..0f40ab7 100644 (file)
@@ -219,20 +219,37 @@ bool Shader::is_constant_emission(float3 *emission)
 {
        ShaderInput *surf = graph->output()->input("Surface");
 
-       if(!surf->link || surf->link->parent->type != EmissionNode::node_type) {
+       if(surf->link == NULL) {
                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("Strength"));
+               assert(node->input("Color"));
+               assert(node->input("Strength"));
 
-       if(node->input("Color")->link || node->input("Strength")->link) {
-               return false;
+               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;
 
-       *emission = node->color*node->strength;
+               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 true;
 }