Code refactor: add generic Cycles node infrastructure.
[blender-staging.git] / intern / cycles / render / svm.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "device.h"
18 #include "graph.h"
19 #include "light.h"
20 #include "mesh.h"
21 #include "nodes.h"
22 #include "scene.h"
23 #include "shader.h"
24 #include "svm.h"
25
26 #include "util_debug.h"
27 #include "util_logging.h"
28 #include "util_foreach.h"
29 #include "util_progress.h"
30
31 CCL_NAMESPACE_BEGIN
32
33 /* Shader Manager */
34
35 SVMShaderManager::SVMShaderManager()
36 {
37 }
38
39 SVMShaderManager::~SVMShaderManager()
40 {
41 }
42
43 void SVMShaderManager::reset(Scene * /*scene*/)
44 {
45 }
46
47 void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
48 {
49         if(!need_update)
50                 return;
51
52         VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
53
54         /* test if we need to update */
55         device_free(device, dscene, scene);
56
57         /* determine which shaders are in use */
58         device_update_shaders_used(scene);
59
60         /* svm_nodes */
61         vector<int4> svm_nodes;
62         size_t i;
63
64         for(i = 0; i < scene->shaders.size(); i++) {
65                 svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
66                 svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
67         }
68         
69         foreach(Shader *shader, scene->shaders) {
70                 if(progress.get_cancel()) return;
71
72                 assert(shader->graph);
73
74                 if(shader->use_mis && shader->has_surface_emission)
75                         scene->light_manager->need_update = true;
76
77                 SVMCompiler::Summary summary;
78                 SVMCompiler compiler(scene->shader_manager, scene->image_manager);
79                 compiler.background = (shader == scene->default_background);
80                 compiler.compile(scene, shader, svm_nodes, shader->id, &summary);
81
82                 VLOG(2) << "Compilation summary:\n"
83                         << "Shader name: " << shader->name << "\n"
84                         << summary.full_report();
85         }
86
87         dscene->svm_nodes.copy((uint4*)&svm_nodes[0], svm_nodes.size());
88         device->tex_alloc("__svm_nodes", dscene->svm_nodes);
89
90         for(i = 0; i < scene->shaders.size(); i++) {
91                 Shader *shader = scene->shaders[i];
92                 shader->need_update = false;
93         }
94
95         device_update_common(device, dscene, scene, progress);
96
97         need_update = false;
98 }
99
100 void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
101 {
102         device_free_common(device, dscene, scene);
103
104         device->tex_free(dscene->svm_nodes);
105         dscene->svm_nodes.clear();
106 }
107
108 /* Graph Compiler */
109
110 SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_manager_)
111 {
112         shader_manager = shader_manager_;
113         image_manager = image_manager_;
114         max_stack_use = 0;
115         current_type = SHADER_TYPE_SURFACE;
116         current_shader = NULL;
117         current_graph = NULL;
118         background = false;
119         mix_weight_offset = SVM_STACK_INVALID;
120         compile_failed = false;
121 }
122
123 int SVMCompiler::stack_size(ShaderSocketType type)
124 {
125         int size = 0;
126         
127         switch(type) {
128                 case SHADER_SOCKET_FLOAT:
129                 case SHADER_SOCKET_INT:
130                         size = 1;
131                         break;
132                 case SHADER_SOCKET_COLOR:
133                 case SHADER_SOCKET_VECTOR:
134                 case SHADER_SOCKET_NORMAL:
135                 case SHADER_SOCKET_POINT:
136                         size = 3;
137                         break;
138                 case SHADER_SOCKET_CLOSURE:
139                         size = 0;
140                         break;
141                 default:
142                         assert(0);
143                         break;
144         }
145         
146         return size;
147 }
148
149 int SVMCompiler::stack_find_offset(ShaderSocketType type)
150 {
151         int size = stack_size(type);
152         int offset = -1;
153         
154         /* find free space in stack & mark as used */
155         for(int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) {
156                 if(active_stack.users[i]) num_unused = 0;
157                 else num_unused++;
158
159                 if(num_unused == size) {
160                         offset = i+1 - size;
161                         max_stack_use = max(i+1, max_stack_use);
162
163                         while(i >= offset)
164                                 active_stack.users[i--] = 1;
165
166                         return offset;
167                 }
168         }
169
170         if(!compile_failed) {
171                 compile_failed = true;
172                 fprintf(stderr, "Cycles: out of SVM stack space, shader \"%s\" too big.\n", current_shader->name.c_str());
173         }
174
175         return 0;
176 }
177
178 void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset)
179 {
180         int size = stack_size(type);
181
182         for(int i = 0; i < size; i++)
183                 active_stack.users[offset + i]--;
184 }
185
186 int SVMCompiler::stack_assign(ShaderInput *input)
187 {
188         /* stack offset assign? */
189         if(input->stack_offset == SVM_STACK_INVALID) {
190                 if(input->link) {
191                         /* linked to output -> use output offset */
192                         input->stack_offset = input->link->stack_offset;
193                 }
194                 else {
195                         /* not linked to output -> add nodes to load default value */
196                         input->stack_offset = stack_find_offset(input->type);
197
198                         if(input->type == SHADER_SOCKET_FLOAT) {
199                                 add_node(NODE_VALUE_F, __float_as_int(input->value.x), input->stack_offset);
200                         }
201                         else if(input->type == SHADER_SOCKET_INT) {
202                                 add_node(NODE_VALUE_F, (int)input->value.x, input->stack_offset);
203                         }
204                         else if(input->type == SHADER_SOCKET_VECTOR ||
205                                 input->type == SHADER_SOCKET_NORMAL ||
206                                 input->type == SHADER_SOCKET_POINT ||
207                                 input->type == SHADER_SOCKET_COLOR)
208                         {
209
210                                 add_node(NODE_VALUE_V, input->stack_offset);
211                                 add_node(NODE_VALUE_V, input->value);
212                         }
213                         else /* should not get called for closure */
214                                 assert(0);
215                 }
216         }
217
218         return input->stack_offset;
219 }
220
221 int SVMCompiler::stack_assign(ShaderOutput *output)
222 {
223         /* if no stack offset assigned yet, find one */
224         if(output->stack_offset == SVM_STACK_INVALID)
225                 output->stack_offset = stack_find_offset(output->type);
226
227         return output->stack_offset;
228 }
229
230 int SVMCompiler::stack_assign_if_linked(ShaderInput *input)
231 {
232         if(input->link)
233                 return stack_assign(input);
234
235         return SVM_STACK_INVALID;
236 }
237
238 int SVMCompiler::stack_assign_if_linked(ShaderOutput *output)
239 {
240         if(!output->links.empty())
241                 return stack_assign(output);
242
243         return SVM_STACK_INVALID;
244 }
245
246 void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output)
247 {
248         if(output->stack_offset == SVM_STACK_INVALID) {
249                 assert(input->link);
250                 assert(stack_size(output->type) == stack_size(input->link->type));
251
252                 output->stack_offset = input->link->stack_offset;
253
254                 int size = stack_size(output->type);
255
256                 for(int i = 0; i < size; i++)
257                         active_stack.users[output->stack_offset + i]++;
258         }
259 }
260
261 void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done)
262 {
263         /* optimization we should add:
264          * find and lower user counts for outputs for which all inputs are done.
265          * this is done before the node is compiled, under the assumption that the
266          * node will first load all inputs from the stack and then writes its
267          * outputs. this used to work, but was disabled because it gave trouble
268          * with inputs getting stack positions assigned */
269
270         foreach(ShaderInput *input, node->inputs) {
271                 ShaderOutput *output = input->link;
272
273                 if(output && output->stack_offset != SVM_STACK_INVALID) {
274                         bool all_done = true;
275
276                         /* optimization we should add: verify if in->parent is actually used */
277                         foreach(ShaderInput *in, output->links)
278                                 if(in->parent != node && done.find(in->parent) == done.end())
279                                         all_done = false;
280
281                         if(all_done) {
282                                 stack_clear_offset(output->type, output->stack_offset);
283                                 output->stack_offset = SVM_STACK_INVALID;
284
285                                 foreach(ShaderInput *in, output->links)
286                                         in->stack_offset = SVM_STACK_INVALID;
287                         }
288                 }
289         }
290 }
291
292 void SVMCompiler::stack_clear_temporary(ShaderNode *node)
293 {
294         foreach(ShaderInput *input, node->inputs) {
295                 if(!input->link && input->stack_offset != SVM_STACK_INVALID) {
296                         stack_clear_offset(input->type, input->stack_offset);
297                         input->stack_offset = SVM_STACK_INVALID;
298                 }
299         }
300 }
301
302 uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w)
303 {
304         assert(x <= 255);
305         assert(y <= 255);
306         assert(z <= 255);
307         assert(w <= 255);
308
309         return (x) | (y << 8) | (z << 16) | (w << 24);
310 }
311
312 void SVMCompiler::add_node(int a, int b, int c, int d)
313 {
314         svm_nodes.push_back(make_int4(a, b, c, d));
315 }
316
317 void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c)
318 {
319         svm_nodes.push_back(make_int4(type, a, b, c));
320 }
321
322 void SVMCompiler::add_node(ShaderNodeType type, const float3& f)
323 {
324         svm_nodes.push_back(make_int4(type,
325                 __float_as_int(f.x),
326                 __float_as_int(f.y),
327                 __float_as_int(f.z)));
328 }
329
330 void SVMCompiler::add_node(const float4& f)
331 {
332         svm_nodes.push_back(make_int4(
333                 __float_as_int(f.x),
334                 __float_as_int(f.y),
335                 __float_as_int(f.z),
336                 __float_as_int(f.w)));
337 }
338
339 uint SVMCompiler::attribute(ustring name)
340 {
341         return shader_manager->get_attribute_id(name);
342 }
343
344 uint SVMCompiler::attribute(AttributeStandard std)
345 {
346         return shader_manager->get_attribute_id(std);
347 }
348
349 bool SVMCompiler::node_skip_input(ShaderNode * /*node*/, ShaderInput *input)
350 {
351         /* nasty exception .. */
352         if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
353                 return true;
354         
355         return false;
356 }
357
358 void SVMCompiler::find_dependencies(ShaderNodeSet& dependencies,
359                                     const ShaderNodeSet& done,
360                                     ShaderInput *input,
361                                     ShaderNode *skip_node)
362 {
363         ShaderNode *node = (input->link)? input->link->parent: NULL;
364
365         if(node != NULL &&
366            done.find(node) == done.end() &&
367            node != skip_node &&
368            dependencies.find(node) == dependencies.end())
369         {
370                 foreach(ShaderInput *in, node->inputs)
371                         if(!node_skip_input(node, in))
372                                 find_dependencies(dependencies, done, in, skip_node);
373
374                 dependencies.insert(node);
375         }
376 }
377
378 void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet& done)
379 {
380         node->compile(*this);
381         stack_clear_users(node, done);
382         stack_clear_temporary(node);
383
384         if(current_type == SHADER_TYPE_SURFACE) {
385                 if(node->has_spatial_varying())
386                         current_shader->has_surface_spatial_varying = true;
387         }
388         else if(current_type == SHADER_TYPE_VOLUME) {
389                 if(node->has_spatial_varying())
390                         current_shader->has_volume_spatial_varying = true;
391         }
392
393         if(node->has_object_dependency()) {
394                 current_shader->has_object_dependency = true;
395         }
396
397         if(node->has_integrator_dependency()) {
398                 current_shader->has_integrator_dependency = true;
399         }
400 }
401
402 void SVMCompiler::generate_svm_nodes(const ShaderNodeSet& nodes,
403                                      CompilerState *state)
404 {
405         ShaderNodeSet& done = state->nodes_done;
406         vector<bool>& done_flag = state->nodes_done_flag;
407
408         bool nodes_done;
409         do {
410                 nodes_done = true;
411
412                 foreach(ShaderNode *node, nodes) {
413                         if(!done_flag[node->id]) {
414                                 bool inputs_done = true;
415
416                                 foreach(ShaderInput *input, node->inputs)
417                                         if(!node_skip_input(node, input))
418                                                 if(input->link && !done_flag[input->link->parent->id])
419                                                         inputs_done = false;
420
421                                 if(inputs_done) {
422                                         generate_node(node, done);
423                                         done.insert(node);
424                                         done_flag[node->id] = true;
425                                 }
426                                 else
427                                         nodes_done = false;
428                         }
429                 }
430         } while(!nodes_done);
431 }
432
433 void SVMCompiler::generate_closure_node(ShaderNode *node,
434                                         CompilerState *state)
435 {
436         /* execute dependencies for closure */
437         foreach(ShaderInput *in, node->inputs) {
438                 if(!node_skip_input(node, in) && in->link) {
439                         ShaderNodeSet dependencies;
440                         find_dependencies(dependencies, state->nodes_done, in);
441                         generate_svm_nodes(dependencies, state);
442                 }
443         }
444
445         /* closure mix weight */
446         const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight";
447         ShaderInput *weight_in = node->input(weight_name);
448
449         if(weight_in && (weight_in->link || weight_in->value.x != 1.0f))
450                 mix_weight_offset = stack_assign(weight_in);
451         else
452                 mix_weight_offset = SVM_STACK_INVALID;
453
454         /* compile closure itself */
455         generate_node(node, state->nodes_done);
456
457         mix_weight_offset = SVM_STACK_INVALID;
458
459         if(current_type == SHADER_TYPE_SURFACE) {
460                 if(node->has_surface_emission())
461                         current_shader->has_surface_emission = true;
462                 if(node->has_surface_transparent())
463                         current_shader->has_surface_transparent = true;
464                 if(node->has_surface_bssrdf()) {
465                         current_shader->has_surface_bssrdf = true;
466                         if(node->has_bssrdf_bump())
467                                 current_shader->has_bssrdf_bump = true;
468                 }
469         }
470 }
471
472 void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
473                                                  ShaderNode *node,
474                                                  CompilerState *state,
475                                                  const ShaderNodeSet& shared)
476 {
477         if(shared.find(node) != shared.end()) {
478                 generate_multi_closure(root_node, node, state);
479         }
480         else {
481                 foreach(ShaderInput *in, node->inputs) {
482                         if(in->type == SHADER_SOCKET_CLOSURE && in->link)
483                                 generated_shared_closure_nodes(root_node,
484                                                                in->link->parent,
485                                                                state,
486                                                                shared);
487                 }
488         }
489 }
490
491 void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
492                                          ShaderNode *node,
493                                          CompilerState *state)
494 {
495         /* only generate once */
496         if(state->closure_done.find(node) != state->closure_done.end())
497                 return;
498
499         state->closure_done.insert(node);
500
501         if(node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
502                 /* weighting is already taken care of in ShaderGraph::transform_multi_closure */
503                 ShaderInput *cl1in = node->input("Closure1");
504                 ShaderInput *cl2in = node->input("Closure2");
505                 ShaderInput *facin = node->input("Fac");
506
507                 /* skip empty mix/add closure nodes */
508                 if(!cl1in->link && !cl2in->link)
509                         return;
510
511                 if(facin && facin->link) {
512                         /* mix closure: generate instructions to compute mix weight */
513                         ShaderNodeSet dependencies;
514                         find_dependencies(dependencies, state->nodes_done, facin);
515                         generate_svm_nodes(dependencies, state);
516
517                         /* execute shared dependencies. this is needed to allow skipping
518                          * of zero weight closures and their dependencies later, so we
519                          * ensure that they only skip dependencies that are unique to them */
520                         ShaderNodeSet cl1deps, cl2deps, shareddeps;
521
522                         find_dependencies(cl1deps, state->nodes_done, cl1in);
523                         find_dependencies(cl2deps, state->nodes_done, cl2in);
524
525                         ShaderNodeIDComparator node_id_comp;
526                         set_intersection(cl1deps.begin(), cl1deps.end(),
527                                          cl2deps.begin(), cl2deps.end(),
528                                          std::inserter(shareddeps, shareddeps.begin()),
529                                          node_id_comp);
530
531                         /* it's possible some nodes are not shared between this mix node
532                          * inputs, but still needed to be always executed, this mainly
533                          * happens when a node of current subbranch is used by a parent
534                          * node or so */
535                         if(root_node != node) {
536                                 foreach(ShaderInput *in, root_node->inputs) {
537                                         ShaderNodeSet rootdeps;
538                                         find_dependencies(rootdeps, state->nodes_done, in, node);
539                                         set_intersection(rootdeps.begin(), rootdeps.end(),
540                                                          cl1deps.begin(), cl1deps.end(),
541                                                          std::inserter(shareddeps, shareddeps.begin()),
542                                                          node_id_comp);
543                                         set_intersection(rootdeps.begin(), rootdeps.end(),
544                                                          cl2deps.begin(), cl2deps.end(),
545                                                          std::inserter(shareddeps, shareddeps.begin()),
546                                                          node_id_comp);
547                                 }
548                         }
549
550                         if(!shareddeps.empty()) {
551                                 if(cl1in->link) {
552                                         generated_shared_closure_nodes(root_node,
553                                                                        cl1in->link->parent,
554                                                                        state,
555                                                                        shareddeps);
556                                 }
557                                 if(cl2in->link) {
558                                         generated_shared_closure_nodes(root_node,
559                                                                        cl2in->link->parent,
560                                                                        state,
561                                                                        shareddeps);
562                                 }
563
564                                 generate_svm_nodes(shareddeps, state);
565                         }
566
567                         /* generate instructions for input closure 1 */
568                         if(cl1in->link) {
569                                 /* add instruction to skip closure and its dependencies if mix weight is zero */
570                                 svm_nodes.push_back(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0));
571                                 int node_jump_skip_index = svm_nodes.size() - 1;
572
573                                 generate_multi_closure(root_node, cl1in->link->parent, state);
574
575                                 /* fill in jump instruction location to be after closure */
576                                 svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1;
577                         }
578
579                         /* generate instructions for input closure 2 */
580                         if(cl2in->link) {
581                                 /* add instruction to skip closure and its dependencies if mix weight is zero */
582                                 svm_nodes.push_back(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0));
583                                 int node_jump_skip_index = svm_nodes.size() - 1;
584
585                                 generate_multi_closure(root_node, cl2in->link->parent, state);
586
587                                 /* fill in jump instruction location to be after closure */
588                                 svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1;
589                         }
590
591                         /* unassign */
592                         facin->stack_offset = SVM_STACK_INVALID;
593                 }
594                 else {
595                         /* execute closures and their dependencies, no runtime checks
596                          * to skip closures here because was already optimized due to
597                          * fixed weight or add closure that always needs both */
598                         if(cl1in->link)
599                                 generate_multi_closure(root_node, cl1in->link->parent, state);
600                         if(cl2in->link)
601                                 generate_multi_closure(root_node, cl2in->link->parent, state);
602                 }
603         }
604         else {
605                 generate_closure_node(node, state);
606         }
607
608         state->nodes_done.insert(node);
609         state->nodes_done_flag[node->id] = true;
610 }
611
612
613 void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
614 {
615         /* Converting a shader graph into svm_nodes that can be executed
616          * sequentially on the virtual machine is fairly simple. We can keep
617          * looping over nodes and each time all the inputs of a node are
618          * ready, we add svm_nodes for it that read the inputs from the
619          * stack and write outputs back to the stack.
620          *
621          * With the SVM, we always sample only a single closure. We can think
622          * of all closures nodes as a binary tree with mix closures as inner
623          * nodes and other closures as leafs. The SVM will traverse that tree,
624          * each time deciding to go left or right depending on the mix weights,
625          * until a closure is found.
626          *
627          * We only execute nodes that are needed for the mix weights and chosen
628          * closure.
629          */
630
631         current_type = type;
632         current_graph = graph;
633
634         /* get input in output node */
635         ShaderNode *node = graph->output();
636         ShaderInput *clin = NULL;
637         
638         switch(type) {
639                 case SHADER_TYPE_SURFACE:
640                         clin = node->input("Surface");
641                         break;
642                 case SHADER_TYPE_VOLUME:
643                         clin = node->input("Volume");
644                         break;
645                 case SHADER_TYPE_DISPLACEMENT:
646                         clin = node->input("Displacement");
647                         break;
648                 default:
649                         assert(0);
650                         break;
651         }
652
653         /* clear all compiler state */
654         memset(&active_stack, 0, sizeof(active_stack));
655         svm_nodes.clear();
656
657         foreach(ShaderNode *node_iter, graph->nodes) {
658                 foreach(ShaderInput *input, node_iter->inputs)
659                         input->stack_offset = SVM_STACK_INVALID;
660                 foreach(ShaderOutput *output, node_iter->outputs)
661                         output->stack_offset = SVM_STACK_INVALID;
662         }
663
664         if(shader->used) {
665                 if(clin->link) {
666                         bool generate = false;
667                         
668                         switch(type) {
669                                 case SHADER_TYPE_SURFACE: /* generate surface shader */         
670                                         generate = true;
671                                         shader->has_surface = true;
672                                         break;
673                                 case SHADER_TYPE_VOLUME: /* generate volume shader */
674                                         generate = true;
675                                         shader->has_volume = true;
676                                         break;
677                                 case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */
678                                         generate = true;
679                                         shader->has_displacement = true;
680                                         break;
681                                 default:
682                                         break;
683                         }
684
685                         if(generate) {
686                                 CompilerState state(graph);
687                                 generate_multi_closure(clin->link->parent,
688                                                        clin->link->parent,
689                                                        &state);
690                         }
691                 }
692
693                 /* compile output node */
694                 node->compile(*this);
695         }
696
697         /* if compile failed, generate empty shader */
698         if(compile_failed) {
699                 svm_nodes.clear();
700                 compile_failed = false;
701         }
702
703         add_node(NODE_END, 0, 0, 0);
704 }
705
706 void SVMCompiler::compile(Scene *scene,
707                           Shader *shader,
708                           vector<int4>& global_svm_nodes,
709                           int index,
710                           Summary *summary)
711 {
712         /* copy graph for shader with bump mapping */
713         ShaderNode *node = shader->graph->output();
714         int start_num_svm_nodes = global_svm_nodes.size();
715
716         const double time_start = time_dt();
717
718         if(node->input("Surface")->link && node->input("Displacement")->link)
719                 if(!shader->graph_bump)
720                         shader->graph_bump = shader->graph->copy();
721
722         /* finalize */
723         {
724                 scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL);
725                 shader->graph->finalize(scene,
726                                         false,
727                                         false,
728                                         shader->has_integrator_dependency);
729         }
730
731         if(shader->graph_bump) {
732                 scoped_timer timer((summary != NULL)? &summary->time_finalize_bump: NULL);
733                 shader->graph_bump->finalize(scene,
734                                              true,
735                                              false,
736                                              shader->has_integrator_dependency);
737         }
738
739         current_shader = shader;
740
741         shader->has_surface = false;
742         shader->has_surface_emission = false;
743         shader->has_surface_transparent = false;
744         shader->has_surface_bssrdf = false;
745         shader->has_bssrdf_bump = false;
746         shader->has_volume = false;
747         shader->has_displacement = false;
748         shader->has_surface_spatial_varying = false;
749         shader->has_volume_spatial_varying = false;
750         shader->has_object_dependency = false;
751         shader->has_integrator_dependency = false;
752
753         /* generate surface shader */
754         {
755                 scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL);
756                 compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
757                 global_svm_nodes[index*2 + 0].y = global_svm_nodes.size();
758                 global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
759                 global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
760         }
761
762         if(shader->graph_bump) {
763                 scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
764                 compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
765                 global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
766                 global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
767         }
768
769         /* generate volume shader */
770         {
771                 scoped_timer timer((summary != NULL)? &summary->time_generate_volume: NULL);
772                 compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
773                 global_svm_nodes[index*2 + 0].z = global_svm_nodes.size();
774                 global_svm_nodes[index*2 + 1].z = global_svm_nodes.size();
775                 global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
776         }
777
778         /* generate displacement shader */
779         {
780                 scoped_timer timer((summary != NULL)? &summary->time_generate_displacement: NULL);
781                 compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
782                 global_svm_nodes[index*2 + 0].w = global_svm_nodes.size();
783                 global_svm_nodes[index*2 + 1].w = global_svm_nodes.size();
784                 global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
785         }
786
787         /* Fill in summary information. */
788         if(summary != NULL) {
789                 summary->time_total = time_dt() - time_start;
790                 summary->peak_stack_usage = max_stack_use;
791                 summary->num_svm_nodes = global_svm_nodes.size() - start_num_svm_nodes;
792         }
793 }
794
795 /* Compiler summary implementation. */
796
797 SVMCompiler::Summary::Summary()
798         : num_svm_nodes(0),
799           peak_stack_usage(0),
800           time_finalize(0.0),
801           time_finalize_bump(0.0),
802           time_generate_surface(0.0),
803           time_generate_bump(0.0),
804           time_generate_volume(0.0),
805           time_generate_displacement(0.0),
806           time_total(0.0)
807 {
808 }
809
810 string SVMCompiler::Summary::full_report() const
811 {
812         string report = "";
813         report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes);
814         report += string_printf("Peak stack usage:    %d\n", peak_stack_usage);
815
816         report += string_printf("Time (in seconds):\n");
817         report += string_printf("  Finalize:          %f\n", time_finalize);
818         report += string_printf("  Bump finalize:     %f\n", time_finalize_bump);
819         report += string_printf("Finalize:            %f\n", time_finalize +
820                                                              time_finalize_bump);
821         report += string_printf("  Surface:           %f\n", time_generate_surface);
822         report += string_printf("  Bump:              %f\n", time_generate_bump);
823         report += string_printf("  Volume:            %f\n", time_generate_volume);
824         report += string_printf("  Displacement:      %f\n", time_generate_displacement);
825         report += string_printf("Generate:            %f\n", time_generate_surface +
826                                                              time_generate_bump +
827                                                              time_generate_volume +
828                                                              time_generate_displacement);
829         report += string_printf("Total:               %f\n", time_total);
830
831         return report;
832 }
833
834 /* Global state of the compiler. */
835
836 SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph)
837 {
838         int max_id = 0;
839         foreach(ShaderNode *node, graph->nodes) {
840                 max_id = max(node->id, max_id);
841         }
842         nodes_done_flag.resize(max_id + 1, false);
843 }
844
845 CCL_NAMESPACE_END
846