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