Blender  V2.93
svm.cpp
Go to the documentation of this file.
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/device.h"
18 
19 #include "render/background.h"
20 #include "render/graph.h"
21 #include "render/light.h"
22 #include "render/mesh.h"
23 #include "render/nodes.h"
24 #include "render/scene.h"
25 #include "render/shader.h"
26 #include "render/stats.h"
27 #include "render/svm.h"
28 
29 #include "util/util_foreach.h"
30 #include "util/util_logging.h"
31 #include "util/util_progress.h"
32 #include "util/util_task.h"
33 
35 
36 /* Shader Manager */
37 
39 {
40 }
41 
43 {
44 }
45 
46 void SVMShaderManager::reset(Scene * /*scene*/)
47 {
48 }
49 
51  Shader *shader,
52  Progress *progress,
53  array<int4> *svm_nodes)
54 {
55  if (progress->get_cancel()) {
56  return;
57  }
58  assert(shader->graph);
59 
60  svm_nodes->push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
61 
62  SVMCompiler::Summary summary;
63  SVMCompiler compiler(scene);
64  compiler.background = (shader == scene->background->get_shader(scene));
65  compiler.compile(shader, *svm_nodes, 0, &summary);
66 
67  VLOG(2) << "Compilation summary:\n"
68  << "Shader name: " << shader->name << "\n"
69  << summary.full_report();
70 }
71 
73  DeviceScene *dscene,
74  Scene *scene,
75  Progress &progress)
76 {
77  if (!need_update())
78  return;
79 
80  scoped_callback_timer timer([scene](double time) {
81  if (scene->update_stats) {
82  scene->update_stats->svm.times.add_entry({"device_update", time});
83  }
84  });
85 
86  const int num_shaders = scene->shaders.size();
87 
88  VLOG(1) << "Total " << num_shaders << " shaders.";
89 
90  double start_time = time_dt();
91 
92  /* test if we need to update */
93  device_free(device, dscene, scene);
94 
95  /* Build all shaders. */
97  vector<array<int4>> shader_svm_nodes(num_shaders);
98  for (int i = 0; i < num_shaders; i++) {
100  this,
101  scene,
102  scene->shaders[i],
103  &progress,
104  &shader_svm_nodes[i]));
105  }
107 
108  if (progress.get_cancel()) {
109  return;
110  }
111 
112  /* The global node list contains a jump table (one node per shader)
113  * followed by the nodes of all shaders. */
114  int svm_nodes_size = num_shaders;
115  for (int i = 0; i < num_shaders; i++) {
116  /* Since we're not copying the local jump node, the size ends up being one node lower. */
117  svm_nodes_size += shader_svm_nodes[i].size() - 1;
118  }
119 
120  int4 *svm_nodes = dscene->svm_nodes.alloc(svm_nodes_size);
121 
122  int node_offset = num_shaders;
123  for (int i = 0; i < num_shaders; i++) {
124  Shader *shader = scene->shaders[i];
125 
126  shader->clear_modified();
127  if (shader->get_use_mis() && shader->has_surface_emission) {
129  }
130 
131  /* Update the global jump table.
132  * Each compiled shader starts with a jump node that has offsets local
133  * to the shader, so copy those and add the offset into the global node list. */
134  int4 &global_jump_node = svm_nodes[shader->id];
135  int4 &local_jump_node = shader_svm_nodes[i][0];
136 
137  global_jump_node.x = NODE_SHADER_JUMP;
138  global_jump_node.y = local_jump_node.y - 1 + node_offset;
139  global_jump_node.z = local_jump_node.z - 1 + node_offset;
140  global_jump_node.w = local_jump_node.w - 1 + node_offset;
141 
142  node_offset += shader_svm_nodes[i].size() - 1;
143  }
144 
145  /* Copy the nodes of each shader into the correct location. */
146  svm_nodes += num_shaders;
147  for (int i = 0; i < num_shaders; i++) {
148  int shader_size = shader_svm_nodes[i].size() - 1;
149 
150  memcpy(svm_nodes, &shader_svm_nodes[i][1], sizeof(int4) * shader_size);
151  svm_nodes += shader_size;
152  }
153 
154  if (progress.get_cancel()) {
155  return;
156  }
157 
158  dscene->svm_nodes.copy_to_device();
159 
160  device_update_common(device, dscene, scene, progress);
161 
162  update_flags = UPDATE_NONE;
163 
164  VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
165  << " seconds.";
166 }
167 
169 {
170  device_free_common(device, dscene, scene);
171 
172  dscene->svm_nodes.free();
173 }
174 
175 /* Graph Compiler */
176 
178 {
179  max_stack_use = 0;
183  background = false;
185  compile_failed = false;
186 }
187 
189 {
190  int size = 0;
191 
192  switch (type) {
193  case SocketType::FLOAT:
194  case SocketType::INT:
195  size = 1;
196  break;
197  case SocketType::COLOR:
198  case SocketType::VECTOR:
199  case SocketType::NORMAL:
200  case SocketType::POINT:
201  size = 3;
202  break;
203  case SocketType::CLOSURE:
204  size = 0;
205  break;
206  default:
207  assert(0);
208  break;
209  }
210 
211  return size;
212 }
213 
215 {
216  int offset = -1;
217 
218  /* find free space in stack & mark as used */
219  for (int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) {
220  if (active_stack.users[i])
221  num_unused = 0;
222  else
223  num_unused++;
224 
225  if (num_unused == size) {
226  offset = i + 1 - size;
227  max_stack_use = max(i + 1, max_stack_use);
228 
229  while (i >= offset)
230  active_stack.users[i--] = 1;
231 
232  return offset;
233  }
234  }
235 
236  if (!compile_failed) {
237  compile_failed = true;
238  fprintf(stderr,
239  "Cycles: out of SVM stack space, shader \"%s\" too big.\n",
240  current_shader->name.c_str());
241  }
242 
243  return 0;
244 }
245 
247 {
249 }
250 
252 {
253  int size = stack_size(type);
254 
255  for (int i = 0; i < size; i++)
256  active_stack.users[offset + i]--;
257 }
258 
260 {
261  /* stack offset assign? */
262  if (input->stack_offset == SVM_STACK_INVALID) {
263  if (input->link) {
264  /* linked to output -> use output offset */
265  assert(input->link->stack_offset != SVM_STACK_INVALID);
266  input->stack_offset = input->link->stack_offset;
267  }
268  else {
269  Node *node = input->parent;
270 
271  /* not linked to output -> add nodes to load default value */
272  input->stack_offset = stack_find_offset(input->type());
273 
274  if (input->type() == SocketType::FLOAT) {
276  __float_as_int(node->get_float(input->socket_type)),
277  input->stack_offset);
278  }
279  else if (input->type() == SocketType::INT) {
280  add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset);
281  }
282  else if (input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL ||
283  input->type() == SocketType::POINT || input->type() == SocketType::COLOR) {
284 
286  add_node(NODE_VALUE_V, node->get_float3(input->socket_type));
287  }
288  else /* should not get called for closure */
289  assert(0);
290  }
291  }
292 
293  return input->stack_offset;
294 }
295 
297 {
298  /* if no stack offset assigned yet, find one */
299  if (output->stack_offset == SVM_STACK_INVALID)
300  output->stack_offset = stack_find_offset(output->type());
301 
302  return output->stack_offset;
303 }
304 
306 {
307  if (input->link)
308  return stack_assign(input);
309 
310  return SVM_STACK_INVALID;
311 }
312 
314 {
315  if (!output->links.empty())
316  return stack_assign(output);
317 
318  return SVM_STACK_INVALID;
319 }
320 
322 {
323  if (output->stack_offset == SVM_STACK_INVALID) {
324  assert(input->link);
325  assert(stack_size(output->type()) == stack_size(input->link->type()));
326 
327  output->stack_offset = input->link->stack_offset;
328 
329  int size = stack_size(output->type());
330 
331  for (int i = 0; i < size; i++)
332  active_stack.users[output->stack_offset + i]++;
333  }
334 }
335 
337 {
338  /* optimization we should add:
339  * find and lower user counts for outputs for which all inputs are done.
340  * this is done before the node is compiled, under the assumption that the
341  * node will first load all inputs from the stack and then writes its
342  * outputs. this used to work, but was disabled because it gave trouble
343  * with inputs getting stack positions assigned */
344 
345  foreach (ShaderInput *input, node->inputs) {
346  ShaderOutput *output = input->link;
347 
348  if (output && output->stack_offset != SVM_STACK_INVALID) {
349  bool all_done = true;
350 
351  /* optimization we should add: verify if in->parent is actually used */
352  foreach (ShaderInput *in, output->links)
353  if (in->parent != node && done.find(in->parent) == done.end())
354  all_done = false;
355 
356  if (all_done) {
357  stack_clear_offset(output->type(), output->stack_offset);
358  output->stack_offset = SVM_STACK_INVALID;
359 
360  foreach (ShaderInput *in, output->links)
361  in->stack_offset = SVM_STACK_INVALID;
362  }
363  }
364  }
365 }
366 
368 {
369  foreach (ShaderInput *input, node->inputs) {
370  if (!input->link && input->stack_offset != SVM_STACK_INVALID) {
371  stack_clear_offset(input->type(), input->stack_offset);
373  }
374  }
375 }
376 
378 {
379  assert(x <= 255);
380  assert(y <= 255);
381  assert(z <= 255);
382  assert(w <= 255);
383 
384  return (x) | (y << 8) | (z << 16) | (w << 24);
385 }
386 
387 void SVMCompiler::add_node(int a, int b, int c, int d)
388 {
390 }
391 
393 {
395 }
396 
398 {
401 }
402 
403 void SVMCompiler::add_node(const float4 &f)
404 {
407 }
408 
410 {
411  return scene->shader_manager->get_attribute_id(name);
412 }
413 
415 {
417 }
418 
420 {
422  return (std) ? attribute(std) : attribute(name);
423 }
424 
426  const ShaderNodeSet &done,
427  ShaderInput *input,
428  ShaderNode *skip_node)
429 {
430  ShaderNode *node = (input->link) ? input->link->parent : NULL;
431  if (node != NULL && done.find(node) == done.end() && node != skip_node &&
432  dependencies.find(node) == dependencies.end()) {
433  foreach (ShaderInput *in, node->inputs) {
434  find_dependencies(dependencies, done, in, skip_node);
435  }
436  dependencies.insert(node);
437  }
438 }
439 
441 {
442  node->compile(*this);
443  stack_clear_users(node, done);
445 
447  if (node->has_spatial_varying())
449  }
450  else if (current_type == SHADER_TYPE_VOLUME) {
451  if (node->has_spatial_varying())
453  if (node->has_attribute_dependency())
455  }
456 
457  if (node->has_integrator_dependency()) {
459  }
460 }
461 
463 {
464  ShaderNodeSet &done = state->nodes_done;
465  vector<bool> &done_flag = state->nodes_done_flag;
466 
467  bool nodes_done;
468  do {
469  nodes_done = true;
470 
471  foreach (ShaderNode *node, nodes) {
472  if (!done_flag[node->id]) {
473  bool inputs_done = true;
474 
475  foreach (ShaderInput *input, node->inputs) {
476  if (input->link && !done_flag[input->link->parent->id]) {
477  inputs_done = false;
478  }
479  }
480  if (inputs_done) {
481  generate_node(node, done);
482  done.insert(node);
483  done_flag[node->id] = true;
484  }
485  else {
486  nodes_done = false;
487  }
488  }
489  }
490  } while (!nodes_done);
491 }
492 
494 {
495  /* execute dependencies for closure */
496  foreach (ShaderInput *in, node->inputs) {
497  if (in->link != NULL) {
498  ShaderNodeSet dependencies;
499  find_dependencies(dependencies, state->nodes_done, in);
500  generate_svm_nodes(dependencies, state);
501  }
502  }
503 
504  /* closure mix weight */
505  const char *weight_name = (current_type == SHADER_TYPE_VOLUME) ? "VolumeMixWeight" :
506  "SurfaceMixWeight";
507  ShaderInput *weight_in = node->input(weight_name);
508 
509  if (weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f))
510  mix_weight_offset = stack_assign(weight_in);
511  else
513 
514  /* compile closure itself */
515  generate_node(node, state->nodes_done);
516 
518 
520  if (node->has_surface_emission())
522  if (node->has_surface_transparent())
524  if (node->has_surface_bssrdf()) {
526  if (node->has_bssrdf_bump())
528  }
529  if (node->has_bump()) {
530  current_shader->has_bump = true;
531  }
532  }
533 }
534 
536  ShaderNode *node,
538  const ShaderNodeSet &shared)
539 {
540  if (shared.find(node) != shared.end()) {
541  generate_multi_closure(root_node, node, state);
542  }
543  else {
544  foreach (ShaderInput *in, node->inputs) {
545  if (in->type() == SocketType::CLOSURE && in->link)
546  generated_shared_closure_nodes(root_node, in->link->parent, state, shared);
547  }
548  }
549 }
550 
554 {
555  foreach (ShaderNode *node, graph->nodes) {
556  if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
557  OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node);
558  if (aov_node->slot >= 0) {
559  aov_nodes.insert(aov_node);
560  foreach (ShaderInput *in, node->inputs) {
561  if (in->link != NULL) {
562  find_dependencies(aov_nodes, state->nodes_done, in);
563  }
564  }
565  }
566  }
567  }
568 }
569 
571  ShaderNode *node,
573 {
574  /* only generate once */
575  if (state->closure_done.find(node) != state->closure_done.end())
576  return;
577 
578  state->closure_done.insert(node);
579 
580  if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
581  /* weighting is already taken care of in ShaderGraph::transform_multi_closure */
582  ShaderInput *cl1in = node->input("Closure1");
583  ShaderInput *cl2in = node->input("Closure2");
584  ShaderInput *facin = node->input("Fac");
585 
586  /* skip empty mix/add closure nodes */
587  if (!cl1in->link && !cl2in->link)
588  return;
589 
590  if (facin && facin->link) {
591  /* mix closure: generate instructions to compute mix weight */
592  ShaderNodeSet dependencies;
593  find_dependencies(dependencies, state->nodes_done, facin);
594  generate_svm_nodes(dependencies, state);
595 
596  /* execute shared dependencies. this is needed to allow skipping
597  * of zero weight closures and their dependencies later, so we
598  * ensure that they only skip dependencies that are unique to them */
599  ShaderNodeSet cl1deps, cl2deps, shareddeps;
600 
601  find_dependencies(cl1deps, state->nodes_done, cl1in);
602  find_dependencies(cl2deps, state->nodes_done, cl2in);
603 
604  ShaderNodeIDComparator node_id_comp;
605  set_intersection(cl1deps.begin(),
606  cl1deps.end(),
607  cl2deps.begin(),
608  cl2deps.end(),
609  std::inserter(shareddeps, shareddeps.begin()),
610  node_id_comp);
611 
612  /* it's possible some nodes are not shared between this mix node
613  * inputs, but still needed to be always executed, this mainly
614  * happens when a node of current subbranch is used by a parent
615  * node or so */
616  if (root_node != node) {
617  foreach (ShaderInput *in, root_node->inputs) {
618  ShaderNodeSet rootdeps;
619  find_dependencies(rootdeps, state->nodes_done, in, node);
620  set_intersection(rootdeps.begin(),
621  rootdeps.end(),
622  cl1deps.begin(),
623  cl1deps.end(),
624  std::inserter(shareddeps, shareddeps.begin()),
625  node_id_comp);
626  set_intersection(rootdeps.begin(),
627  rootdeps.end(),
628  cl2deps.begin(),
629  cl2deps.end(),
630  std::inserter(shareddeps, shareddeps.begin()),
631  node_id_comp);
632  }
633  }
634 
635  /* For dependencies AOV nodes, prevent them from being categorized
636  * as exclusive deps of one or the other closure, since the need to
637  * execute them for AOV writing is not dependent on the closure
638  * weights. */
639  if (state->aov_nodes.size()) {
640  set_intersection(state->aov_nodes.begin(),
641  state->aov_nodes.end(),
642  cl1deps.begin(),
643  cl1deps.end(),
644  std::inserter(shareddeps, shareddeps.begin()),
645  node_id_comp);
646  set_intersection(state->aov_nodes.begin(),
647  state->aov_nodes.end(),
648  cl2deps.begin(),
649  cl2deps.end(),
650  std::inserter(shareddeps, shareddeps.begin()),
651  node_id_comp);
652  }
653 
654  if (!shareddeps.empty()) {
655  if (cl1in->link) {
656  generated_shared_closure_nodes(root_node, cl1in->link->parent, state, shareddeps);
657  }
658  if (cl2in->link) {
659  generated_shared_closure_nodes(root_node, cl2in->link->parent, state, shareddeps);
660  }
661 
662  generate_svm_nodes(shareddeps, state);
663  }
664 
665  /* generate instructions for input closure 1 */
666  if (cl1in->link) {
667  /* Add instruction to skip closure and its dependencies if mix
668  * weight is zero.
669  */
671  int node_jump_skip_index = current_svm_nodes.size() - 1;
672 
673  generate_multi_closure(root_node, cl1in->link->parent, state);
674 
675  /* Fill in jump instruction location to be after closure. */
676  current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
677  node_jump_skip_index - 1;
678  }
679 
680  /* generate instructions for input closure 2 */
681  if (cl2in->link) {
682  /* Add instruction to skip closure and its dependencies if mix
683  * weight is zero.
684  */
686  int node_jump_skip_index = current_svm_nodes.size() - 1;
687 
688  generate_multi_closure(root_node, cl2in->link->parent, state);
689 
690  /* Fill in jump instruction location to be after closure. */
691  current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
692  node_jump_skip_index - 1;
693  }
694 
695  /* unassign */
697  }
698  else {
699  /* execute closures and their dependencies, no runtime checks
700  * to skip closures here because was already optimized due to
701  * fixed weight or add closure that always needs both */
702  if (cl1in->link)
703  generate_multi_closure(root_node, cl1in->link->parent, state);
704  if (cl2in->link)
705  generate_multi_closure(root_node, cl2in->link->parent, state);
706  }
707  }
708  else {
710  }
711 
712  state->nodes_done.insert(node);
713  state->nodes_done_flag[node->id] = true;
714 }
715 
717 {
718  /* Converting a shader graph into svm_nodes that can be executed
719  * sequentially on the virtual machine is fairly simple. We can keep
720  * looping over nodes and each time all the inputs of a node are
721  * ready, we add svm_nodes for it that read the inputs from the
722  * stack and write outputs back to the stack.
723  *
724  * With the SVM, we always sample only a single closure. We can think
725  * of all closures nodes as a binary tree with mix closures as inner
726  * nodes and other closures as leafs. The SVM will traverse that tree,
727  * each time deciding to go left or right depending on the mix weights,
728  * until a closure is found.
729  *
730  * We only execute nodes that are needed for the mix weights and chosen
731  * closure.
732  */
733 
734  current_type = type;
736 
737  /* get input in output node */
738  ShaderNode *output = graph->output();
739  ShaderInput *clin = NULL;
740 
741  switch (type) {
742  case SHADER_TYPE_SURFACE:
743  clin = output->input("Surface");
744  break;
745  case SHADER_TYPE_VOLUME:
746  clin = output->input("Volume");
747  break;
749  clin = output->input("Displacement");
750  break;
751  case SHADER_TYPE_BUMP:
752  clin = output->input("Normal");
753  break;
754  default:
755  assert(0);
756  break;
757  }
758 
759  /* clear all compiler state */
760  memset((void *)&active_stack, 0, sizeof(active_stack));
762 
763  foreach (ShaderNode *node, graph->nodes) {
764  foreach (ShaderInput *input, node->inputs)
766  foreach (ShaderOutput *output, node->outputs)
767  output->stack_offset = SVM_STACK_INVALID;
768  }
769 
770  /* for the bump shader we need add a node to store the shader state */
771  bool need_bump_state = (type == SHADER_TYPE_BUMP) &&
772  (shader->get_displacement_method() == DISPLACE_BOTH);
773  int bump_state_offset = SVM_STACK_INVALID;
774  if (need_bump_state) {
775  bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
776  add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
777  }
778 
779  if (shader->used) {
781  if (clin->link) {
782  bool generate = false;
783 
784  switch (type) {
785  case SHADER_TYPE_SURFACE: /* generate surface shader */
786  generate = true;
787  shader->has_surface = true;
788  break;
789  case SHADER_TYPE_VOLUME: /* generate volume shader */
790  generate = true;
791  shader->has_volume = true;
792  break;
793  case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */
794  generate = true;
795  shader->has_displacement = true;
796  break;
797  case SHADER_TYPE_BUMP: /* generate bump shader */
798  generate = true;
799  break;
800  default:
801  break;
802  }
803 
804  if (generate) {
805  if (type == SHADER_TYPE_SURFACE) {
807  }
809  }
810  }
811 
812  /* compile output node */
813  output->compile(*this);
814 
815  if (!state.aov_nodes.empty()) {
816  /* AOV passes are only written if the object is directly visible, so
817  * there is no point in evaluating all the nodes generated only for the
818  * AOV outputs if that's not the case. Therefore, we insert
819  * NODE_AOV_START into the shader before the AOV-only nodes are
820  * generated which tells the kernel that it can stop evaluation
821  * early if AOVs will not be written. */
822  add_node(NODE_AOV_START, 0, 0, 0);
823  generate_svm_nodes(state.aov_nodes, &state);
824  }
825  }
826 
827  /* add node to restore state after bump shader has finished */
828  if (need_bump_state) {
829  add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset);
830  }
831 
832  /* if compile failed, generate empty shader */
833  if (compile_failed) {
835  compile_failed = false;
836  }
837 
838  /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader
839  * it ends here */
840  if (type != SHADER_TYPE_BUMP) {
841  add_node(NODE_END, 0, 0, 0);
842  }
843 }
844 
845 void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary)
846 {
847  /* copy graph for shader with bump mapping */
848  ShaderNode *output = shader->graph->output();
849  int start_num_svm_nodes = svm_nodes.size();
850 
851  const double time_start = time_dt();
852 
853  bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
854  output->input("Surface")->link && output->input("Displacement")->link;
855 
856  /* finalize */
857  {
858  scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL);
859  shader->graph->finalize(scene,
860  has_bump,
861  shader->has_integrator_dependency,
862  shader->get_displacement_method() == DISPLACE_BOTH);
863  }
864 
866 
867  shader->has_surface = false;
868  shader->has_surface_emission = false;
869  shader->has_surface_transparent = false;
870  shader->has_surface_bssrdf = false;
871  shader->has_bump = has_bump;
872  shader->has_bssrdf_bump = has_bump;
873  shader->has_volume = false;
874  shader->has_displacement = false;
875  shader->has_surface_spatial_varying = false;
876  shader->has_volume_spatial_varying = false;
877  shader->has_volume_attribute_dependency = false;
878  shader->has_integrator_dependency = false;
879 
880  /* generate bump shader */
881  if (has_bump) {
882  scoped_timer timer((summary != NULL) ? &summary->time_generate_bump : NULL);
884  svm_nodes[index].y = svm_nodes.size();
885  svm_nodes.append(current_svm_nodes);
886  }
887 
888  /* generate surface shader */
889  {
890  scoped_timer timer((summary != NULL) ? &summary->time_generate_surface : NULL);
892  /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this
893  * one if it exists */
894  if (!has_bump) {
895  svm_nodes[index].y = svm_nodes.size();
896  }
897  svm_nodes.append(current_svm_nodes);
898  }
899 
900  /* generate volume shader */
901  {
902  scoped_timer timer((summary != NULL) ? &summary->time_generate_volume : NULL);
904  svm_nodes[index].z = svm_nodes.size();
905  svm_nodes.append(current_svm_nodes);
906  }
907 
908  /* generate displacement shader */
909  {
910  scoped_timer timer((summary != NULL) ? &summary->time_generate_displacement : NULL);
912  svm_nodes[index].w = svm_nodes.size();
913  svm_nodes.append(current_svm_nodes);
914  }
915 
916  /* Fill in summary information. */
917  if (summary != NULL) {
918  summary->time_total = time_dt() - time_start;
919  summary->peak_stack_usage = max_stack_use;
920  summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes;
921  }
922 }
923 
924 /* Compiler summary implementation. */
925 
927  : num_svm_nodes(0),
928  peak_stack_usage(0),
929  time_finalize(0.0),
930  time_generate_surface(0.0),
931  time_generate_bump(0.0),
932  time_generate_volume(0.0),
933  time_generate_displacement(0.0),
934  time_total(0.0)
935 {
936 }
937 
939 {
940  string report = "";
941  report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes);
942  report += string_printf("Peak stack usage: %d\n", peak_stack_usage);
943 
944  report += string_printf("Time (in seconds):\n");
945  report += string_printf("Finalize: %f\n", time_finalize);
946  report += string_printf(" Surface: %f\n", time_generate_surface);
947  report += string_printf(" Bump: %f\n", time_generate_bump);
948  report += string_printf(" Volume: %f\n", time_generate_volume);
949  report += string_printf(" Displacement: %f\n", time_generate_displacement);
950  report += string_printf("Generate: %f\n",
951  time_generate_surface + time_generate_bump + time_generate_volume +
952  time_generate_displacement);
953  report += string_printf("Total: %f\n", time_total);
954 
955  return report;
956 }
957 
958 /* Global state of the compiler. */
959 
961 {
962  int max_id = 0;
963  foreach (ShaderNode *node, graph->nodes) {
964  max_id = max(node->id, max_id);
965  }
966  nodes_done_flag.resize(max_id + 1, false);
967 }
968 
unsigned int uint
Definition: BLI_sys_types.h:83
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
#define output
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
static AttributeStandard name_standard(const char *name)
Definition: attribute.cpp:373
Shader * get_shader(const Scene *scene)
device_vector< int4 > svm_nodes
Definition: scene.h:124
Definition: device.h:293
@ SHADER_COMPILED
Definition: light.h:102
void tag_update(Scene *scene, uint32_t flag)
Definition: light.cpp:1036
int slot
Definition: nodes.h:238
bool get_cancel()
ShaderGraph * current_graph
Definition: render/svm.h:125
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
Definition: svm.cpp:716
int max_stack_use
Definition: render/svm.h:225
void find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes, ShaderGraph *graph, CompilerState *state)
Definition: svm.cpp:551
void add_node(ShaderNodeType type, int a=0, int b=0, int c=0)
Definition: svm.cpp:392
bool background
Definition: render/svm.h:126
SVMCompiler(Scene *scene)
Definition: svm.cpp:177
array< int4 > current_svm_nodes
Definition: render/svm.h:221
void generate_closure_node(ShaderNode *node, CompilerState *state)
Definition: svm.cpp:493
void stack_clear_offset(SocketType::Type type, int offset)
Definition: svm.cpp:251
ShaderType current_type
Definition: render/svm.h:222
void generate_node(ShaderNode *node, ShaderNodeSet &done)
Definition: svm.cpp:440
int stack_assign_if_linked(ShaderInput *input)
Definition: svm.cpp:305
Shader * current_shader
Definition: render/svm.h:223
void stack_clear_users(ShaderNode *node, ShaderNodeSet &done)
Definition: svm.cpp:336
int stack_size(SocketType::Type type)
Definition: svm.cpp:188
void stack_clear_temporary(ShaderNode *node)
Definition: svm.cpp:367
uint encode_uchar4(uint x, uint y=0, uint z=0, uint w=0)
Definition: svm.cpp:377
uint attribute_standard(ustring name)
Definition: svm.cpp:419
Stack active_stack
Definition: render/svm.h:224
void stack_link(ShaderInput *input, ShaderOutput *output)
Definition: svm.cpp:321
void find_dependencies(ShaderNodeSet &dependencies, const ShaderNodeSet &done, ShaderInput *input, ShaderNode *skip_node=NULL)
Definition: svm.cpp:425
void generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state)
Definition: svm.cpp:462
void generate_multi_closure(ShaderNode *root_node, ShaderNode *node, CompilerState *state)
Definition: svm.cpp:570
uint attribute(ustring name)
Definition: svm.cpp:409
Scene * scene
Definition: render/svm.h:124
uint mix_weight_offset
Definition: render/svm.h:226
bool compile_failed
Definition: render/svm.h:227
int stack_find_offset(int size)
Definition: svm.cpp:214
void compile(Shader *shader, array< int4 > &svm_nodes, int index, Summary *summary=NULL)
Definition: svm.cpp:845
void generated_shared_closure_nodes(ShaderNode *root_node, ShaderNode *node, CompilerState *state, const ShaderNodeSet &shared)
Definition: svm.cpp:535
int stack_assign(ShaderOutput *output)
Definition: svm.cpp:296
void reset(Scene *scene)
Definition: svm.cpp:46
void device_free(Device *device, DeviceScene *dscene, Scene *scene)
Definition: svm.cpp:168
SVMShaderManager()
Definition: svm.cpp:38
~SVMShaderManager()
Definition: svm.cpp:42
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress)
Definition: svm.cpp:72
void device_update_shader(Scene *scene, Shader *shader, Progress *progress, array< int4 > *svm_nodes)
Definition: svm.cpp:50
ShaderOutput * link
Definition: graph.h:112
int stack_offset
Definition: graph.h:113
ShaderNode * parent
Definition: graph.h:111
SocketType::Type type()
Definition: graph.h:94
const SocketType & socket_type
Definition: graph.h:110
uint get_attribute_id(ustring name)
Definition: shader.cpp:429
bool need_update() const
Definition: shader.cpp:796
void device_free_common(Device *device, DeviceScene *dscene, Scene *scene)
Definition: shader.cpp:618
int id
Definition: graph.h:226
vector< ShaderInput * > inputs
Definition: graph.h:223
SocketType::Type type()
Definition: graph.h:131
int stack_offset
Definition: graph.h:141
ShaderNode * parent
Definition: graph.h:139
Definition: shader.h:80
bool has_surface_spatial_varying
Definition: shader.h:125
bool has_surface_bssrdf
Definition: shader.h:122
bool has_volume_attribute_dependency
Definition: shader.h:127
bool has_bssrdf_bump
Definition: shader.h:124
bool has_integrator_dependency
Definition: shader.h:128
bool has_surface_emission
Definition: shader.h:118
bool has_bump
Definition: shader.h:123
bool has_surface_transparent
Definition: shader.h:119
bool has_volume_spatial_varying
Definition: shader.h:126
void append(const array< T > &from)
Definition: util_array.h:278
size_t size() const
Definition: util_array.h:203
void push_back_slow(const T &t)
Definition: util_array.h:263
void clear()
Definition: util_array.h:188
int x
Definition: btConvexHull.h:149
int w
Definition: btConvexHull.h:149
int y
Definition: btConvexHull.h:149
int z
Definition: btConvexHull.h:149
OperationNode * node
Depsgraph * graph
double time
Scene scene
#define function_bind
TaskPool * task_pool
@ SHADER_SPECIAL_TYPE_OUTPUT_AOV
Definition: graph.h:70
@ SHADER_SPECIAL_TYPE_COMBINE_CLOSURE
Definition: graph.h:67
set< ShaderNode *, ShaderNodeIDComparator > ShaderNodeSet
Definition: graph.h:307
#define CCL_NAMESPACE_END
#define make_int4(x, y, z, w)
void KERNEL_FUNCTION_FULL_NAME() shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int filter, int i, int offset, int sample)
AttributeStandard
Definition: kernel_types.h:744
static ulong state[N]
static char * generate(GHash *messages, size_t *r_output_size)
Definition: msgfmt.c:186
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
@ DISPLACE_TRUE
Definition: shader.h:68
@ DISPLACE_BOTH
Definition: shader.h:69
Definition: node.h:98
ustring name
Definition: node.h:174
CompilerState(ShaderGraph *graph)
Definition: svm.cpp:960
int users[SVM_STACK_SIZE]
Definition: render/svm.h:164
double time_generate_volume
Definition: render/svm.h:82
double time_generate_surface
Definition: render/svm.h:76
double time_generate_bump
Definition: render/svm.h:79
string full_report() const
Definition: svm.cpp:938
double time_generate_displacement
Definition: render/svm.h:85
vector< Shader * > shaders
Definition: scene.h:236
Background * background
Definition: scene.h:230
ShaderManager * shader_manager
Definition: scene.h:245
LightManager * light_manager
Definition: scene.h:244
SceneUpdateStats * update_stats
Definition: scene.h:270
void push(TaskRunFunction &&task)
Definition: util_task.cpp:36
void wait_work(Summary *stats=NULL)
Definition: util_task.cpp:42
float z
Definition: sky_float3.h:35
float y
Definition: sky_float3.h:35
float x
Definition: sky_float3.h:35
#define SVM_STACK_SIZE
Definition: svm_types.h:25
ShaderNodeType
Definition: svm_types.h:64
@ NODE_AOV_START
Definition: svm_types.h:153
@ NODE_VALUE_V
Definition: svm_types.h:80
@ NODE_LEAVE_BUMP_EVAL
Definition: svm_types.h:100
@ NODE_END
Definition: svm_types.h:65
@ NODE_VALUE_F
Definition: svm_types.h:79
@ NODE_SHADER_JUMP
Definition: svm_types.h:66
@ NODE_JUMP_IF_ONE
Definition: svm_types.h:75
@ NODE_ENTER_BUMP_EVAL
Definition: svm_types.h:99
@ NODE_JUMP_IF_ZERO
Definition: svm_types.h:74
ShaderType
Definition: svm_types.h:511
@ SHADER_TYPE_BUMP
Definition: svm_types.h:515
@ SHADER_TYPE_SURFACE
Definition: svm_types.h:512
@ SHADER_TYPE_VOLUME
Definition: svm_types.h:513
@ SHADER_TYPE_DISPLACEMENT
Definition: svm_types.h:514
#define SVM_BUMP_EVAL_STATE_SIZE
Definition: svm_types.h:29
#define SVM_STACK_INVALID
Definition: svm_types.h:27
float max
#define VLOG(severity)
Definition: util_logging.h:50
ccl_device_inline int __float_as_int(float f)
Definition: util_math.h:202
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition: util_string.cpp:32
CCL_NAMESPACE_BEGIN double time_dt()
Definition: util_time.cpp:48