Cycles: Optimize shaders earlier to skip unneccessary attributes for noninteractive...
authorLukas Stockner <lukas.stockner@freenet.de>
Wed, 14 Dec 2016 22:47:39 +0000 (23:47 +0100)
committerLukas Stockner <lukas.stockner@freenet.de>
Mon, 27 Mar 2017 03:36:49 +0000 (05:36 +0200)
Before, Cycles would first sync the shader exactly as shown in the UI, then determine and sync the used attributes and later optimize the shader.
Therefore, even completely unconnected nodes would cause unneccessary attributes to be synced.

The reason for this is to avoid frequent resyncs when editing shaders interactively, but it can still be avoided for noninteractive renders - which is what this commit does.

Reviewed by: sergey

Differential Revision: https://developer.blender.org/D2285

intern/cycles/blender/blender_shader.cpp
intern/cycles/render/graph.cpp
intern/cycles/render/graph.h
intern/cycles/render/osl.cpp
intern/cycles/render/svm.cpp

index 8baa53fc2ec759322a23a1ace04ba94a19ddf0eb..f35565d8330bc64012d62e6a45235266cd705699 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "util_debug.h"
 #include "util_string.h"
+#include "util_task.h"
 
 CCL_NAMESPACE_BEGIN
 
@@ -1164,6 +1165,8 @@ void BlenderSync::sync_materials(bool update_all)
        /* material loop */
        BL::BlendData::materials_iterator b_mat;
 
+       TaskPool pool;
+
        for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
                Shader *shader;
 
@@ -1199,9 +1202,22 @@ void BlenderSync::sync_materials(bool update_all)
                        shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP;
 
                        shader->set_graph(graph);
+
+                       /* By simplifying the shader graph as soon as possible, some redundant shader nodes
+                        * might be removed which prevents loading unneccessary attributes later.
+                        *
+                        * However, since graph simplification also accounts for e.g. mix weight, this would
+                        * cause frequent expensive resyncs in interactive sessions, so for those sessions
+                        * optimization is only performed right before compiling. */
+                       if(!preview) {
+                               pool.push(function_bind(&ShaderGraph::simplify, shader->graph, scene));
+                       }
+
                        shader->tag_update(scene);
                }
        }
+
+       pool.wait_work();
 }
 
 /* Sync World */
index f6c83fb5c7e355418052ec8d6695e4f43699b877..0cfd08090c2e7baab38e741c698c0f442aaffa1d 100644 (file)
@@ -17,6 +17,7 @@
 #include "attribute.h"
 #include "graph.h"
 #include "nodes.h"
+#include "scene.h"
 #include "shader.h"
 #include "constant_fold.h"
 
@@ -195,6 +196,7 @@ bool ShaderNode::equals(const ShaderNode& other)
 ShaderGraph::ShaderGraph()
 {
        finalized = false;
+       simplified = false;
        num_node_ids = 0;
        add(new OutputNode());
 }
@@ -207,6 +209,8 @@ ShaderGraph::~ShaderGraph()
 ShaderNode *ShaderGraph::add(ShaderNode *node)
 {
        assert(!finalized);
+       simplified = false;
+
        node->id = num_node_ids++;
        nodes.push_back(node);
        return node;
@@ -241,6 +245,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
 {
        assert(!finalized);
        assert(from && to);
+       simplified = false;
 
        if(to->link) {
                fprintf(stderr, "Cycles shader graph connect: input already connected.\n");
@@ -273,6 +278,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
 void ShaderGraph::disconnect(ShaderOutput *from)
 {
        assert(!finalized);
+       simplified = false;
 
        foreach(ShaderInput *sock, from->links) {
                sock->link = NULL;
@@ -285,6 +291,7 @@ void ShaderGraph::disconnect(ShaderInput *to)
 {
        assert(!finalized);
        assert(to->link);
+       simplified = false;
 
        ShaderOutput *from = to->link;
 
@@ -294,6 +301,8 @@ void ShaderGraph::disconnect(ShaderInput *to)
 
 void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
 {
+       simplified = false;
+
        /* Copy because disconnect modifies this list */
        vector<ShaderInput*> outputs = from->links;
 
@@ -310,9 +319,19 @@ void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
        }
 }
 
+void ShaderGraph::simplify(Scene *scene)
+{
+       if(!simplified) {
+               default_inputs(scene->shader_manager->use_osl());
+               clean(scene);
+               refine_bump_nodes();
+
+               simplified = true;
+       }
+}
+
 void ShaderGraph::finalize(Scene *scene,
                            bool do_bump,
-                           bool do_osl,
                            bool do_simplify,
                            bool bump_in_object_space)
 {
@@ -322,9 +341,7 @@ void ShaderGraph::finalize(Scene *scene,
         * modified afterwards. */
 
        if(!finalized) {
-               default_inputs(do_osl);
-               clean(scene);
-               refine_bump_nodes();
+               simplify(scene);
 
                if(do_bump)
                        bump_from_displacement(bump_in_object_space);
index 06524d3fa132c67b9b1db0f692f8ea57bb35ff7a..d22193d4e51dff0737520b8a1a0ad1b8a48e5641 100644 (file)
@@ -240,6 +240,7 @@ public:
        list<ShaderNode*> nodes;
        size_t num_node_ids;
        bool finalized;
+       bool simplified;
 
        ShaderGraph();
        ~ShaderGraph();
@@ -255,9 +256,9 @@ public:
        void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
 
        void remove_proxy_nodes();
+       void simplify(Scene *scene);
        void finalize(Scene *scene,
                      bool do_bump = false,
-                     bool do_osl = false,
                      bool do_simplify = false,
                      bool bump_in_object_space = false);
 
index 67b68e63cb2211b8af59419a866ecf3d2e8ed541..68bd8d96bf953ba4e1129274e768295e67f78cfe 100644 (file)
@@ -1096,11 +1096,9 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
                /* finalize */
                shader->graph->finalize(scene,
                                        false,
-                                       true,
                                        shader->has_integrator_dependency);
                if(shader->graph_bump) {
                        shader->graph_bump->finalize(scene,
-                                                    true,
                                                     true,
                                                     shader->has_integrator_dependency,
                                                     shader->displacement_method == DISPLACE_BOTH);
index 955b892f4c34193b05d1606487595c58d8a089fa..bbf14c24b56af6be7d6c86ae8b9e6a5e56616ee6 100644 (file)
@@ -812,7 +812,6 @@ void SVMCompiler::compile(Scene *scene,
        {
                scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL);
                shader->graph->finalize(scene,
-                                       false,
                                        false,
                                        shader->has_integrator_dependency);
        }
@@ -821,7 +820,6 @@ void SVMCompiler::compile(Scene *scene,
                scoped_timer timer((summary != NULL)? &summary->time_finalize_bump: NULL);
                shader->graph_bump->finalize(scene,
                                             true,
-                                            false,
                                             shader->has_integrator_dependency,
                                             shader->displacement_method == DISPLACE_BOTH);
        }