diff options
Diffstat (limited to 'intern/cycles/render/svm.cpp')
-rw-r--r-- | intern/cycles/render/svm.cpp | 268 |
1 files changed, 194 insertions, 74 deletions
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index d0bd34915df..f3d39c1bd72 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -76,9 +76,14 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene if(shader->use_mis && shader->has_surface_emission) scene->light_manager->need_update = true; + SVMCompiler::Summary summary; SVMCompiler compiler(scene->shader_manager, scene->image_manager); compiler.background = ((int)i == scene->default_background); - compiler.compile(shader, svm_nodes, i); + compiler.compile(scene, shader, svm_nodes, i, &summary); + + VLOG(1) << "Compilation summary:\n" + << "Shader name: " << shader->name << "\n" + << summary.full_report(); } dscene->svm_nodes.copy((uint4*)&svm_nodes[0], svm_nodes.size()); @@ -121,7 +126,7 @@ int SVMCompiler::stack_size(ShaderSocketType type) { int size = 0; - switch (type) { + switch(type) { case SHADER_SOCKET_FLOAT: case SHADER_SOCKET_INT: size = 1; @@ -180,7 +185,7 @@ void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset) active_stack.users[offset + i]--; } -void SVMCompiler::stack_backup(StackBackup& backup, set<ShaderNode*>& done) +void SVMCompiler::stack_backup(StackBackup& backup, ShaderNodeSet& done) { backup.done = done; backup.stack = active_stack; @@ -193,7 +198,7 @@ void SVMCompiler::stack_backup(StackBackup& backup, set<ShaderNode*>& done) } } -void SVMCompiler::stack_restore(StackBackup& backup, set<ShaderNode*>& done) +void SVMCompiler::stack_restore(StackBackup& backup, ShaderNodeSet& done) { int i = 0; @@ -263,7 +268,7 @@ void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output) } } -void SVMCompiler::stack_clear_users(ShaderNode *node, set<ShaderNode*>& done) +void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done) { /* optimization we should add: * find and lower user counts for outputs for which all inputs are done. @@ -366,14 +371,18 @@ bool SVMCompiler::node_skip_input(ShaderNode * /*node*/, ShaderInput *input) return false; } -void SVMCompiler::find_dependencies(set<ShaderNode*>& dependencies, - const set<ShaderNode*>& done, +void SVMCompiler::find_dependencies(ShaderNodeSet& dependencies, + const ShaderNodeSet& done, ShaderInput *input, ShaderNode *skip_node) { ShaderNode *node = (input->link)? input->link->parent: NULL; - if(node && done.find(node) == done.end() && node != skip_node) { + if(node != NULL && + done.find(node) == done.end() && + node != skip_node && + dependencies.find(node) == dependencies.end()) + { foreach(ShaderInput *in, node->inputs) if(!node_skip_input(node, in)) find_dependencies(dependencies, done, in, skip_node); @@ -382,41 +391,53 @@ void SVMCompiler::find_dependencies(set<ShaderNode*>& dependencies, } } -void SVMCompiler::generate_node(ShaderNode *node, set<ShaderNode*>& done) +void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet& done) { node->compile(*this); stack_clear_users(node, done); stack_clear_temporary(node); - if(current_type == SHADER_TYPE_VOLUME) { + if(current_type == SHADER_TYPE_SURFACE) { if(node->has_spatial_varying()) - current_shader->has_heterogeneous_volume = true; + current_shader->has_surface_spatial_varying = true; + } + else if(current_type == SHADER_TYPE_VOLUME) { + if(node->has_spatial_varying()) + current_shader->has_volume_spatial_varying = true; } if(node->has_object_dependency()) { current_shader->has_object_dependency = true; } + + if(node->has_integrator_dependency()) { + current_shader->has_integrator_dependency = true; + } } -void SVMCompiler::generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNode*>& done) +void SVMCompiler::generate_svm_nodes(const ShaderNodeSet& nodes, + CompilerState *state) { - bool nodes_done; + ShaderNodeSet& done = state->nodes_done; + vector<bool>& done_flag = state->nodes_done_flag; + bool nodes_done; do { nodes_done = true; foreach(ShaderNode *node, nodes) { - if(done.find(node) == done.end()) { + if(!done_flag[node->id]) { bool inputs_done = true; foreach(ShaderInput *input, node->inputs) if(!node_skip_input(node, input)) - if(input->link && done.find(input->link->parent) == done.end()) + if(input->link && !done_flag[input->link->parent->id]) inputs_done = false; if(inputs_done) { generate_node(node, done); done.insert(node); + done_flag[node->id] = true; } else nodes_done = false; @@ -425,14 +446,15 @@ void SVMCompiler::generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNo } while(!nodes_done); } -void SVMCompiler::generate_closure_node(ShaderNode *node, set<ShaderNode*>& done) +void SVMCompiler::generate_closure_node(ShaderNode *node, + CompilerState *state) { /* execute dependencies for closure */ foreach(ShaderInput *in, node->inputs) { if(!node_skip_input(node, in) && in->link) { - set<ShaderNode*> dependencies; - find_dependencies(dependencies, done, in); - generate_svm_nodes(dependencies, done); + ShaderNodeSet dependencies; + find_dependencies(dependencies, state->nodes_done, in); + generate_svm_nodes(dependencies, state); } } @@ -448,7 +470,7 @@ void SVMCompiler::generate_closure_node(ShaderNode *node, set<ShaderNode*>& done mix_weight_offset = SVM_STACK_INVALID; /* compile closure itself */ - generate_node(node, done); + generate_node(node, state->nodes_done); mix_weight_offset = SVM_STACK_INVALID; @@ -467,32 +489,32 @@ void SVMCompiler::generate_closure_node(ShaderNode *node, set<ShaderNode*>& done void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node, ShaderNode *node, - set<ShaderNode*>& done, - set<ShaderNode*>& closure_done, - const set<ShaderNode*>& shared) + CompilerState *state, + const ShaderNodeSet& shared) { if(shared.find(node) != shared.end()) { - generate_multi_closure(root_node, node, done, closure_done); + generate_multi_closure(root_node, node, state); } else { foreach(ShaderInput *in, node->inputs) { if(in->type == SHADER_SOCKET_CLOSURE && in->link) - generated_shared_closure_nodes(root_node, in->link->parent, - done, closure_done, shared); + generated_shared_closure_nodes(root_node, + in->link->parent, + state, + shared); } } } void SVMCompiler::generate_multi_closure(ShaderNode *root_node, ShaderNode *node, - set<ShaderNode*>& done, - set<ShaderNode*>& closure_done) + CompilerState *state) { /* only generate once */ - if(closure_done.find(node) != closure_done.end()) + if(state->closure_done.find(node) != state->closure_done.end()) return; - closure_done.insert(node); + state->closure_done.insert(node); if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) { /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ @@ -506,23 +528,25 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, if(facin && facin->link) { /* mix closure: generate instructions to compute mix weight */ - set<ShaderNode*> dependencies; - find_dependencies(dependencies, done, facin); - generate_svm_nodes(dependencies, done); + ShaderNodeSet dependencies; + find_dependencies(dependencies, state->nodes_done, facin); + generate_svm_nodes(dependencies, state); stack_assign(facin); /* execute shared dependencies. this is needed to allow skipping * of zero weight closures and their dependencies later, so we * ensure that they only skip dependencies that are unique to them */ - set<ShaderNode*> cl1deps, cl2deps, shareddeps; + ShaderNodeSet cl1deps, cl2deps, shareddeps; - find_dependencies(cl1deps, done, cl1in); - find_dependencies(cl2deps, done, cl2in); + find_dependencies(cl1deps, state->nodes_done, cl1in); + find_dependencies(cl2deps, state->nodes_done, cl2in); + ShaderNodeIDComparator node_id_comp; set_intersection(cl1deps.begin(), cl1deps.end(), cl2deps.begin(), cl2deps.end(), - std::inserter(shareddeps, shareddeps.begin())); + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); /* it's possible some nodes are not shared between this mix node * inputs, but still needed to be always executed, this mainly @@ -530,28 +554,34 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, * node or so */ if(root_node != node) { foreach(ShaderInput *in, root_node->inputs) { - set<ShaderNode*> rootdeps; - find_dependencies(rootdeps, done, in, node); + ShaderNodeSet rootdeps; + find_dependencies(rootdeps, state->nodes_done, in, node); set_intersection(rootdeps.begin(), rootdeps.end(), cl1deps.begin(), cl1deps.end(), - std::inserter(shareddeps, shareddeps.begin())); + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); set_intersection(rootdeps.begin(), rootdeps.end(), cl2deps.begin(), cl2deps.end(), - std::inserter(shareddeps, shareddeps.begin())); + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); } } if(!shareddeps.empty()) { if(cl1in->link) { - generated_shared_closure_nodes(root_node, cl1in->link->parent, - done, closure_done, shareddeps); + generated_shared_closure_nodes(root_node, + cl1in->link->parent, + state, + shareddeps); } if(cl2in->link) { - generated_shared_closure_nodes(root_node, cl2in->link->parent, - done, closure_done, shareddeps); + generated_shared_closure_nodes(root_node, + cl2in->link->parent, + state, + shareddeps); } - generate_svm_nodes(shareddeps, done); + generate_svm_nodes(shareddeps, state); } /* generate instructions for input closure 1 */ @@ -560,7 +590,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, svm_nodes.push_back(make_int4(NODE_JUMP_IF_ONE, 0, facin->stack_offset, 0)); int node_jump_skip_index = svm_nodes.size() - 1; - generate_multi_closure(root_node, cl1in->link->parent, done, closure_done); + generate_multi_closure(root_node, cl1in->link->parent, state); /* fill in jump instruction location to be after closure */ svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1; @@ -572,7 +602,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, svm_nodes.push_back(make_int4(NODE_JUMP_IF_ZERO, 0, facin->stack_offset, 0)); int node_jump_skip_index = svm_nodes.size() - 1; - generate_multi_closure(root_node, cl2in->link->parent, done, closure_done); + generate_multi_closure(root_node, cl2in->link->parent, state); /* fill in jump instruction location to be after closure */ svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1; @@ -586,16 +616,17 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, * to skip closures here because was already optimized due to * fixed weight or add closure that always needs both */ if(cl1in->link) - generate_multi_closure(root_node, cl1in->link->parent, done, closure_done); + generate_multi_closure(root_node, cl1in->link->parent, state); if(cl2in->link) - generate_multi_closure(root_node, cl2in->link->parent, done, closure_done); + generate_multi_closure(root_node, cl2in->link->parent, state); } } else { - generate_closure_node(node, done); + generate_closure_node(node, state); } - done.insert(node); + state->nodes_done.insert(node); + state->nodes_done_flag[node->id] = true; } @@ -624,7 +655,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty ShaderNode *node = graph->output(); ShaderInput *clin = NULL; - switch (type) { + switch(type) { case SHADER_TYPE_SURFACE: clin = node->input("Surface"); break; @@ -654,7 +685,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty if(clin->link) { bool generate = false; - switch (type) { + switch(type) { case SHADER_TYPE_SURFACE: /* generate surface shader */ generate = true; shader->has_surface = true; @@ -672,9 +703,10 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty } if(generate) { - set<ShaderNode*> done, closure_done; - generate_multi_closure(clin->link->parent, clin->link->parent, - done, closure_done); + CompilerState state(graph); + generate_multi_closure(clin->link->parent, + clin->link->parent, + &state); } } @@ -691,19 +723,38 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty add_node(NODE_END, 0, 0, 0); } -void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int index) +void SVMCompiler::compile(Scene *scene, + Shader *shader, + vector<int4>& global_svm_nodes, + int index, + Summary *summary) { /* copy graph for shader with bump mapping */ ShaderNode *node = shader->graph->output(); + int start_num_svm_nodes = global_svm_nodes.size(); + + const double time_start = time_dt(); if(node->input("Surface")->link && node->input("Displacement")->link) if(!shader->graph_bump) shader->graph_bump = shader->graph->copy(); /* finalize */ - shader->graph->finalize(false, false); - if(shader->graph_bump) - shader->graph_bump->finalize(true, false); + { + scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL); + shader->graph->finalize(scene, + false, + false, + shader->has_integrator_dependency); + } + + if(shader->graph_bump) { + scoped_timer timer((summary != NULL)? &summary->time_finalize_bump: NULL); + shader->graph_bump->finalize(scene, + true, + false, + shader->has_integrator_dependency); + } current_shader = shader; @@ -714,32 +765,101 @@ void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int in shader->has_bssrdf_bump = false; shader->has_volume = false; shader->has_displacement = false; - shader->has_heterogeneous_volume = false; + shader->has_surface_spatial_varying = false; + shader->has_volume_spatial_varying = false; shader->has_object_dependency = false; + shader->has_integrator_dependency = false; /* generate surface shader */ - compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); - global_svm_nodes[index*2 + 0].y = global_svm_nodes.size(); - global_svm_nodes[index*2 + 1].y = global_svm_nodes.size(); - global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end()); + { + scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL); + compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); + global_svm_nodes[index*2 + 0].y = global_svm_nodes.size(); + global_svm_nodes[index*2 + 1].y = global_svm_nodes.size(); + global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end()); + } if(shader->graph_bump) { + scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL); compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE); global_svm_nodes[index*2 + 1].y = global_svm_nodes.size(); global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end()); } /* generate volume shader */ - compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); - global_svm_nodes[index*2 + 0].z = global_svm_nodes.size(); - global_svm_nodes[index*2 + 1].z = global_svm_nodes.size(); - global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end()); + { + scoped_timer timer((summary != NULL)? &summary->time_generate_volume: NULL); + compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); + global_svm_nodes[index*2 + 0].z = global_svm_nodes.size(); + global_svm_nodes[index*2 + 1].z = global_svm_nodes.size(); + global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end()); + } /* generate displacement shader */ - compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); - global_svm_nodes[index*2 + 0].w = global_svm_nodes.size(); - global_svm_nodes[index*2 + 1].w = global_svm_nodes.size(); - global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end()); + { + scoped_timer timer((summary != NULL)? &summary->time_generate_displacement: NULL); + compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); + global_svm_nodes[index*2 + 0].w = global_svm_nodes.size(); + global_svm_nodes[index*2 + 1].w = global_svm_nodes.size(); + global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end()); + } + + /* Fill in summary information. */ + if(summary != NULL) { + summary->time_total = time_dt() - time_start; + summary->peak_stack_usage = max_stack_use; + summary->num_svm_nodes = global_svm_nodes.size() - start_num_svm_nodes; + } +} + +/* Compiler summary implementation. */ + +SVMCompiler::Summary::Summary() + : num_svm_nodes(0), + peak_stack_usage(0), + time_finalize(0.0), + time_finalize_bump(0.0), + time_generate_surface(0.0), + time_generate_bump(0.0), + time_generate_volume(0.0), + time_generate_displacement(0.0), + time_total(0.0) +{ +} + +string SVMCompiler::Summary::full_report() const +{ + string report = ""; + report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes); + report += string_printf("Peak stack usage: %d\n", peak_stack_usage); + + report += string_printf("Time (in seconds):\n"); + report += string_printf(" Finalize: %f\n", time_finalize); + report += string_printf(" Bump finalize: %f\n", time_finalize_bump); + report += string_printf("Finalize: %f\n", time_finalize + + time_finalize_bump); + report += string_printf(" Surface: %f\n", time_generate_surface); + report += string_printf(" Bump: %f\n", time_generate_bump); + report += string_printf(" Volume: %f\n", time_generate_volume); + report += string_printf(" Displacement: %f\n", time_generate_displacement); + report += string_printf("Generate: %f\n", time_generate_surface + + time_generate_bump + + time_generate_volume + + time_generate_displacement); + report += string_printf("Total: %f\n", time_total); + + return report; +} + +/* Global state of the compiler. */ + +SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph) +{ + int max_id = 0; + foreach(ShaderNode *node, graph->nodes) { + max_id = max(node->id, max_id); + } + nodes_done_flag.resize(max_id + 1, false); } CCL_NAMESPACE_END |