Blender V4.3
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 "device/device.h"
6
7#include "scene/background.h"
8#include "scene/light.h"
9#include "scene/mesh.h"
10#include "scene/scene.h"
11#include "scene/shader.h"
12#include "scene/shader_graph.h"
13#include "scene/shader_nodes.h"
14#include "scene/stats.h"
15#include "scene/svm.h"
16
17#include "util/foreach.h"
18#include "util/log.h"
19#include "util/progress.h"
20#include "util/task.h"
21
23
24/* Shader Manager */
25
27
29
30void SVMShaderManager::reset(Scene * /*scene*/) {}
31
33 Shader *shader,
34 Progress *progress,
35 array<int4> *svm_nodes)
36{
37 if (progress->get_cancel()) {
38 return;
39 }
40 assert(shader->graph);
41
43 SVMCompiler compiler(scene);
44 compiler.background = (shader == scene->background->get_shader(scene));
45 compiler.compile(shader, *svm_nodes, 0, &summary);
46
47 VLOG_WORK << "Compilation summary:\n"
48 << "Shader name: " << shader->name << "\n"
49 << summary.full_report();
50}
51
53 DeviceScene *dscene,
54 Scene *scene,
55 Progress &progress)
56{
57 if (!need_update()) {
58 return;
59 }
60
61 scoped_callback_timer timer([scene](double time) {
62 if (scene->update_stats) {
63 scene->update_stats->svm.times.add_entry({"device_update", time});
64 }
65 });
66
67 const int num_shaders = scene->shaders.size();
68
69 VLOG_INFO << "Total " << num_shaders << " shaders.";
70
71 double start_time = time_dt();
72
73 /* test if we need to update */
74 device_free(device, dscene, scene);
75
76 /* Build all shaders. */
78 vector<array<int4>> shader_svm_nodes(num_shaders);
79 for (int i = 0; i < num_shaders; i++) {
81 this,
82 scene,
83 scene->shaders[i],
84 &progress,
85 &shader_svm_nodes[i]));
86 }
88
89 if (progress.get_cancel()) {
90 return;
91 }
92
93 /* The global node list contains a jump table (one node per shader)
94 * followed by the nodes of all shaders. */
95 int svm_nodes_size = num_shaders;
96 for (int i = 0; i < num_shaders; i++) {
97 /* Since we're not copying the local jump node, the size ends up being one node lower. */
98 svm_nodes_size += shader_svm_nodes[i].size() - 1;
99 }
100
101 int4 *svm_nodes = dscene->svm_nodes.alloc(svm_nodes_size);
102
103 int node_offset = num_shaders;
104 for (int i = 0; i < num_shaders; i++) {
105 Shader *shader = scene->shaders[i];
106
107 shader->clear_modified();
108 if (shader->emission_sampling != EMISSION_SAMPLING_NONE) {
109 scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
110 }
111
112 /* Update the global jump table.
113 * Each compiled shader starts with a jump node that has offsets local
114 * to the shader, so copy those and add the offset into the global node list. */
115 int4 &global_jump_node = svm_nodes[shader->id];
116 int4 &local_jump_node = shader_svm_nodes[i][0];
117
118 global_jump_node.x = NODE_SHADER_JUMP;
119 global_jump_node.y = local_jump_node.y - 1 + node_offset;
120 global_jump_node.z = local_jump_node.z - 1 + node_offset;
121 global_jump_node.w = local_jump_node.w - 1 + node_offset;
122
123 node_offset += shader_svm_nodes[i].size() - 1;
124 }
125
126 /* Copy the nodes of each shader into the correct location. */
127 svm_nodes += num_shaders;
128 for (int i = 0; i < num_shaders; i++) {
129 int shader_size = shader_svm_nodes[i].size() - 1;
130
131 memcpy(svm_nodes, &shader_svm_nodes[i][1], sizeof(int4) * shader_size);
132 svm_nodes += shader_size;
133 }
134
135 if (progress.get_cancel()) {
136 return;
137 }
138
139 dscene->svm_nodes.copy_to_device();
140
141 device_update_common(device, dscene, scene, progress);
142
143 update_flags = UPDATE_NONE;
144
145 VLOG_INFO << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
146 << " seconds.";
147}
148
150{
151 device_free_common(device, dscene, scene);
152
153 dscene->svm_nodes.free();
154}
155
156/* Graph Compiler */
157
158SVMCompiler::SVMCompiler(Scene *scene) : scene(scene)
159{
160 max_stack_use = 0;
164 background = false;
167 compile_failed = false;
168
169 /* This struct has one entry for every node, in order of ShaderNodeType definition. */
170 svm_node_types_used = (std::atomic_int *)&scene->dscene.data.svm_usage;
171}
172
174{
175 int size = 0;
176
177 switch (type) {
179 case SocketType::INT:
180 size = 1;
181 break;
186 size = 3;
187 break;
189 size = 0;
190 break;
191 default:
192 assert(0);
193 break;
194 }
195
196 return size;
197}
198
200{
201 int offset = -1;
202
203 /* find free space in stack & mark as used */
204 for (int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) {
205 if (active_stack.users[i]) {
206 num_unused = 0;
207 }
208 else {
209 num_unused++;
210 }
211
212 if (num_unused == size) {
213 offset = i + 1 - size;
215
216 while (i >= offset) {
217 active_stack.users[i--] = 1;
218 }
219
220 return offset;
221 }
222 }
223
224 if (!compile_failed) {
225 compile_failed = true;
226 fprintf(stderr,
227 "Cycles: out of SVM stack space, shader \"%s\" too big.\n",
228 current_shader->name.c_str());
229 }
230
231 return 0;
232}
233
238
240{
241 int size = stack_size(type);
242
243 for (int i = 0; i < size; i++) {
244 active_stack.users[offset + i]--;
245 }
246}
247
249{
250 /* stack offset assign? */
251 if (input->stack_offset == SVM_STACK_INVALID) {
252 if (input->link) {
253 /* linked to output -> use output offset */
254 assert(input->link->stack_offset != SVM_STACK_INVALID);
255 input->stack_offset = input->link->stack_offset;
256 }
257 else {
258 Node *node = input->parent;
259
260 /* not linked to output -> add nodes to load default value */
261 input->stack_offset = stack_find_offset(input->type());
262
263 if (input->type() == SocketType::FLOAT) {
264 add_node(NODE_VALUE_F,
265 __float_as_int(node->get_float(input->socket_type)),
266 input->stack_offset);
267 }
268 else if (input->type() == SocketType::INT) {
269 add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset);
270 }
271 else if (input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL ||
272 input->type() == SocketType::POINT || input->type() == SocketType::COLOR)
273 {
274
275 add_node(NODE_VALUE_V, input->stack_offset);
276 add_node(NODE_VALUE_V, node->get_float3(input->socket_type));
277 }
278 else { /* should not get called for closure */
279 assert(0);
280 }
281 }
282 }
283
284 return input->stack_offset;
285}
286
288{
289 /* if no stack offset assigned yet, find one */
290 if (output->stack_offset == SVM_STACK_INVALID) {
291 output->stack_offset = stack_find_offset(output->type());
292 }
293
294 return output->stack_offset;
295}
296
298{
299 return (input->link || input->constant_folded_in);
300}
301
303{
304 if (is_linked(input)) {
305 return stack_assign(input);
306 }
307
308 return SVM_STACK_INVALID;
309}
310
312{
313 if (!output->links.empty()) {
314 return stack_assign(output);
315 }
316
317 return SVM_STACK_INVALID;
318}
319
321{
322 if (output->stack_offset == SVM_STACK_INVALID) {
323 assert(input->link);
324 assert(stack_size(output->type()) == stack_size(input->link->type()));
325
326 output->stack_offset = input->link->stack_offset;
327
328 int size = stack_size(output->type());
329
330 for (int i = 0; i < size; i++) {
331 active_stack.users[output->stack_offset + i]++;
332 }
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
357 if (all_done) {
358 stack_clear_offset(output->type(), output->stack_offset);
359 output->stack_offset = SVM_STACK_INVALID;
360
361 foreach (ShaderInput *in, output->links)
362 in->stack_offset = SVM_STACK_INVALID;
363 }
364 }
365 }
366}
367
369{
370 foreach (ShaderInput *input, node->inputs) {
371 if (!input->link && input->stack_offset != SVM_STACK_INVALID) {
372 stack_clear_offset(input->type(), input->stack_offset);
373 input->stack_offset = SVM_STACK_INVALID;
374 }
375 }
376}
377
379{
380 assert(x <= 255);
381 assert(y <= 255);
382 assert(z <= 255);
383 assert(w <= 255);
384
385 return (x) | (y << 8) | (z << 16) | (w << 24);
386}
387
388void SVMCompiler::add_node(int a, int b, int c, int d)
389{
391}
392
393void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c)
394{
395 svm_node_types_used[type] = true;
397}
398
405
411
413{
414 return scene->shader_manager->get_attribute_id(name);
415}
416
418{
419 return scene->shader_manager->get_attribute_id(std);
420}
421
423{
425 return (std) ? attribute(std) : attribute(name);
426}
427
429 const ShaderNodeSet &done,
430 ShaderInput *input,
431 ShaderNode *skip_node)
432{
433 ShaderNode *node = (input->link) ? input->link->parent : NULL;
434 if (node != NULL && done.find(node) == done.end() && node != skip_node &&
435 dependencies.find(node) == dependencies.end())
436 {
437 foreach (ShaderInput *in, node->inputs) {
438 find_dependencies(dependencies, done, in, skip_node);
439 }
440 dependencies.insert(node);
441 }
442}
443
445{
446 node->compile(*this);
447 stack_clear_users(node, done);
449
451 if (node->has_spatial_varying()) {
453 }
454 if (node->get_feature() & KERNEL_FEATURE_NODE_RAYTRACE) {
456 }
457 }
458 else if (current_type == SHADER_TYPE_VOLUME) {
459 if (node->has_spatial_varying()) {
461 }
462 if (node->has_attribute_dependency()) {
464 }
465 }
466}
467
469{
470 ShaderNodeSet &done = state->nodes_done;
471 vector<bool> &done_flag = state->nodes_done_flag;
472
473 bool nodes_done;
474 do {
475 nodes_done = true;
476
477 foreach (ShaderNode *node, nodes) {
478 if (!done_flag[node->id]) {
479 bool inputs_done = true;
480
481 foreach (ShaderInput *input, node->inputs) {
482 if (input->link && !done_flag[input->link->parent->id]) {
483 inputs_done = false;
484 }
485 }
486 if (inputs_done) {
487 generate_node(node, done);
488 done.insert(node);
489 done_flag[node->id] = true;
490 }
491 else {
492 nodes_done = false;
493 }
494 }
495 }
496 } while (!nodes_done);
497}
498
500{
501 /* Skip generating closure that are not supported or needed for a particular
502 * type of shader. For example a BSDF in a volume shader. */
503 const int node_feature = node->get_feature();
504 if ((state->node_feature_mask & node_feature) != node_feature) {
505 return;
506 }
507
508 /* execute dependencies for closure */
509 foreach (ShaderInput *in, node->inputs) {
510 if (in->link != NULL) {
511 ShaderNodeSet dependencies;
512 find_dependencies(dependencies, state->nodes_done, in);
513 generate_svm_nodes(dependencies, state);
514 }
515 }
516
517 /* closure mix weight */
518 const char *weight_name = (current_type == SHADER_TYPE_VOLUME) ? "VolumeMixWeight" :
519 "SurfaceMixWeight";
520 ShaderInput *weight_in = node->input(weight_name);
521
522 if (weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f)) {
523 mix_weight_offset = stack_assign(weight_in);
524 }
525 else {
527 }
528
529 /* compile closure itself */
530 generate_node(node, state->nodes_done);
531
533
535 if (node->has_surface_transparent()) {
537 }
538 if (node->has_surface_bssrdf()) {
540 if (node->has_bssrdf_bump()) {
542 }
543 }
544 if (node->has_bump()) {
545 current_shader->has_bump = true;
546 }
547 }
548}
549
551 ShaderNode *node,
553 const ShaderNodeSet &shared)
554{
555 if (shared.find(node) != shared.end()) {
556 generate_multi_closure(root_node, node, state);
557 }
558 else {
559 foreach (ShaderInput *in, node->inputs) {
560 if (in->type() == SocketType::CLOSURE && in->link) {
561 generated_shared_closure_nodes(root_node, in->link->parent, state, shared);
562 }
563 }
564 }
565}
566
568 ShaderGraph *graph,
570{
571 foreach (ShaderNode *node, graph->nodes) {
572 if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
573 OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node);
574 if (aov_node->offset >= 0) {
575 aov_nodes.insert(aov_node);
576 foreach (ShaderInput *in, node->inputs) {
577 if (in->link != NULL) {
578 find_dependencies(aov_nodes, state->nodes_done, in);
579 }
580 }
581 }
582 }
583 }
584}
585
587 ShaderNode *node,
589{
590 /* only generate once */
591 if (state->closure_done.find(node) != state->closure_done.end()) {
592 return;
593 }
594
595 state->closure_done.insert(node);
596
597 if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
598 /* weighting is already taken care of in ShaderGraph::transform_multi_closure */
599 ShaderInput *cl1in = node->input("Closure1");
600 ShaderInput *cl2in = node->input("Closure2");
601 ShaderInput *facin = node->input("Fac");
602
603 /* skip empty mix/add closure nodes */
604 if (!cl1in->link && !cl2in->link) {
605 return;
606 }
607
608 if (facin && facin->link) {
609 /* mix closure: generate instructions to compute mix weight */
610 ShaderNodeSet dependencies;
611 find_dependencies(dependencies, state->nodes_done, facin);
612 generate_svm_nodes(dependencies, state);
613
614 /* execute shared dependencies. this is needed to allow skipping
615 * of zero weight closures and their dependencies later, so we
616 * ensure that they only skip dependencies that are unique to them */
617 ShaderNodeSet cl1deps, cl2deps, shareddeps;
618
619 find_dependencies(cl1deps, state->nodes_done, cl1in);
620 find_dependencies(cl2deps, state->nodes_done, cl2in);
621
622 ShaderNodeIDComparator node_id_comp;
623 set_intersection(cl1deps.begin(),
624 cl1deps.end(),
625 cl2deps.begin(),
626 cl2deps.end(),
627 std::inserter(shareddeps, shareddeps.begin()),
628 node_id_comp);
629
630 /* it's possible some nodes are not shared between this mix node
631 * inputs, but still needed to be always executed, this mainly
632 * happens when a node of current subbranch is used by a parent
633 * node or so */
634 if (root_node != node) {
635 foreach (ShaderInput *in, root_node->inputs) {
636 ShaderNodeSet rootdeps;
637 find_dependencies(rootdeps, state->nodes_done, in, node);
638 set_intersection(rootdeps.begin(),
639 rootdeps.end(),
640 cl1deps.begin(),
641 cl1deps.end(),
642 std::inserter(shareddeps, shareddeps.begin()),
643 node_id_comp);
644 set_intersection(rootdeps.begin(),
645 rootdeps.end(),
646 cl2deps.begin(),
647 cl2deps.end(),
648 std::inserter(shareddeps, shareddeps.begin()),
649 node_id_comp);
650 }
651 }
652
653 /* For dependencies AOV nodes, prevent them from being categorized
654 * as exclusive deps of one or the other closure, since the need to
655 * execute them for AOV writing is not dependent on the closure
656 * weights. */
657 if (state->aov_nodes.size()) {
658 set_intersection(state->aov_nodes.begin(),
659 state->aov_nodes.end(),
660 cl1deps.begin(),
661 cl1deps.end(),
662 std::inserter(shareddeps, shareddeps.begin()),
663 node_id_comp);
664 set_intersection(state->aov_nodes.begin(),
665 state->aov_nodes.end(),
666 cl2deps.begin(),
667 cl2deps.end(),
668 std::inserter(shareddeps, shareddeps.begin()),
669 node_id_comp);
670 }
671
672 if (!shareddeps.empty()) {
673 if (cl1in->link) {
674 generated_shared_closure_nodes(root_node, cl1in->link->parent, state, shareddeps);
675 }
676 if (cl2in->link) {
677 generated_shared_closure_nodes(root_node, cl2in->link->parent, state, shareddeps);
678 }
679
680 generate_svm_nodes(shareddeps, state);
681 }
682
683 /* generate instructions for input closure 1 */
684 if (cl1in->link) {
685 /* Add instruction to skip closure and its dependencies if mix
686 * weight is zero.
687 */
688 svm_node_types_used[NODE_JUMP_IF_ONE] = true;
689 current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0));
690 int node_jump_skip_index = current_svm_nodes.size() - 1;
691
692 generate_multi_closure(root_node, cl1in->link->parent, state);
693
694 /* Fill in jump instruction location to be after closure. */
695 current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
696 node_jump_skip_index - 1;
697 }
698
699 /* generate instructions for input closure 2 */
700 if (cl2in->link) {
701 /* Add instruction to skip closure and its dependencies if mix
702 * weight is zero.
703 */
704 svm_node_types_used[NODE_JUMP_IF_ZERO] = true;
705 current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0));
706 int node_jump_skip_index = current_svm_nodes.size() - 1;
707
708 generate_multi_closure(root_node, cl2in->link->parent, state);
709
710 /* Fill in jump instruction location to be after closure. */
711 current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
712 node_jump_skip_index - 1;
713 }
714
715 /* unassign */
717 }
718 else {
719 /* execute closures and their dependencies, no runtime checks
720 * to skip closures here because was already optimized due to
721 * fixed weight or add closure that always needs both */
722 if (cl1in->link) {
723 generate_multi_closure(root_node, cl1in->link->parent, state);
724 }
725 if (cl2in->link) {
726 generate_multi_closure(root_node, cl2in->link->parent, state);
727 }
728 }
729 }
730 else {
732 }
733
734 state->nodes_done.insert(node);
735 state->nodes_done_flag[node->id] = true;
736}
737
739{
740 /* Converting a shader graph into svm_nodes that can be executed
741 * sequentially on the virtual machine is fairly simple. We can keep
742 * looping over nodes and each time all the inputs of a node are
743 * ready, we add svm_nodes for it that read the inputs from the
744 * stack and write outputs back to the stack.
745 *
746 * With the SVM, we always sample only a single closure. We can think
747 * of all closures nodes as a binary tree with mix closures as inner
748 * nodes and other closures as leafs. The SVM will traverse that tree,
749 * each time deciding to go left or right depending on the mix weights,
750 * until a closure is found.
751 *
752 * We only execute nodes that are needed for the mix weights and chosen
753 * closure.
754 */
755
756 current_type = type;
758
759 /* get input in output node */
760 ShaderNode *output = graph->output();
761 ShaderInput *clin = NULL;
762
763 switch (type) {
765 clin = output->input("Surface");
766 break;
768 clin = output->input("Volume");
769 break;
771 clin = output->input("Displacement");
772 break;
773 case SHADER_TYPE_BUMP:
774 clin = output->input("Normal");
775 break;
776 default:
777 assert(0);
778 break;
779 }
780
781 /* clear all compiler state */
782 memset((void *)&active_stack, 0, sizeof(active_stack));
784
785 foreach (ShaderNode *node, graph->nodes) {
786 foreach (ShaderInput *input, node->inputs)
787 input->stack_offset = SVM_STACK_INVALID;
788 foreach (ShaderOutput *output, node->outputs)
789 output->stack_offset = SVM_STACK_INVALID;
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) {
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
870void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary)
871{
872 svm_node_types_used[NODE_SHADER_JUMP] = true;
873 svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
874
875 /* copy graph for shader with bump mapping */
876 ShaderNode *output = shader->graph->output();
877 int start_num_svm_nodes = svm_nodes.size();
878
879 const double time_start = time_dt();
880
881 bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
882 output->input("Surface")->link && output->input("Displacement")->link;
883
884 /* finalize */
885 {
886 scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL);
887 shader->graph->finalize(scene, has_bump, shader->get_displacement_method() == DISPLACE_BOTH);
888 }
889
890 current_shader = shader;
891
892 shader->has_surface = false;
893 shader->has_surface_transparent = false;
894 shader->has_surface_raytrace = false;
895 shader->has_surface_bssrdf = false;
896 shader->has_bump = has_bump;
897 shader->has_bssrdf_bump = has_bump;
898 shader->has_volume = false;
899 shader->has_displacement = false;
900 shader->has_surface_spatial_varying = false;
901 shader->has_volume_spatial_varying = false;
902 shader->has_volume_attribute_dependency = false;
903
904 /* generate bump shader */
905 if (has_bump) {
906 scoped_timer timer((summary != NULL) ? &summary->time_generate_bump : NULL);
907 compile_type(shader, shader->graph, SHADER_TYPE_BUMP);
908 svm_nodes[index].y = svm_nodes.size();
909 svm_nodes.append(current_svm_nodes);
910 }
911
912 /* generate surface shader */
913 {
914 scoped_timer timer((summary != NULL) ? &summary->time_generate_surface : NULL);
915 compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
916 /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this
917 * one if it exists */
918 if (!has_bump) {
919 svm_nodes[index].y = svm_nodes.size();
920 }
921 svm_nodes.append(current_svm_nodes);
922 }
923
924 /* generate volume shader */
925 {
926 scoped_timer timer((summary != NULL) ? &summary->time_generate_volume : NULL);
927 compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
928 svm_nodes[index].z = svm_nodes.size();
929 svm_nodes.append(current_svm_nodes);
930 }
931
932 /* generate displacement shader */
933 {
934 scoped_timer timer((summary != NULL) ? &summary->time_generate_displacement : NULL);
935 compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
936 svm_nodes[index].w = svm_nodes.size();
937 svm_nodes.append(current_svm_nodes);
938 }
939
940 /* Fill in summary information. */
941 if (summary != NULL) {
942 summary->time_total = time_dt() - time_start;
944 summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes;
945 }
946
947 /* Estimate emission for MIS. */
948 shader->estimate_emission();
949}
950
951/* Compiler summary implementation. */
952
954 : num_svm_nodes(0),
955 peak_stack_usage(0),
956 time_finalize(0.0),
957 time_generate_surface(0.0),
958 time_generate_bump(0.0),
959 time_generate_volume(0.0),
960 time_generate_displacement(0.0),
961 time_total(0.0)
962{
963}
964
966{
967 string report = "";
968 report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes);
969 report += string_printf("Peak stack usage: %d\n", peak_stack_usage);
970
971 report += string_printf("Time (in seconds):\n");
972 report += string_printf("Finalize: %f\n", time_finalize);
973 report += string_printf(" Surface: %f\n", time_generate_surface);
974 report += string_printf(" Bump: %f\n", time_generate_bump);
975 report += string_printf(" Volume: %f\n", time_generate_volume);
976 report += string_printf(" Displacement: %f\n", time_generate_displacement);
977 report += string_printf("Generate: %f\n",
978 time_generate_surface + time_generate_bump + time_generate_volume +
979 time_generate_displacement);
980 report += string_printf("Total: %f\n", time_total);
981
982 return report;
983}
984
985/* Global state of the compiler. */
986
988{
989 int max_id = 0;
990 foreach (ShaderNode *node, graph->nodes) {
991 max_id = max(node->id, max_id);
992 }
993 nodes_done_flag.resize(max_id + 1, false);
994 node_feature_mask = 0;
995}
996
unsigned int uint
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
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
static AttributeStandard name_standard(const char *name)
device_vector< int4 > svm_nodes
Definition devicescene.h:83
bool get_cancel() const
Definition progress.h:93
ShaderGraph * current_graph
Definition scene/svm.h:121
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
Definition svm.cpp:738
int max_stack_use
Definition scene/svm.h:228
void find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes, ShaderGraph *graph, CompilerState *state)
Definition svm.cpp:567
void add_node(ShaderNodeType type, int a=0, int b=0, int c=0)
Definition svm.cpp:393
bool background
Definition scene/svm.h:122
SVMCompiler(Scene *scene)
Definition svm.cpp:158
array< int4 > current_svm_nodes
Definition scene/svm.h:224
void generate_closure_node(ShaderNode *node, CompilerState *state)
Definition svm.cpp:499
void stack_clear_offset(SocketType::Type type, int offset)
Definition svm.cpp:239
ShaderType current_type
Definition scene/svm.h:225
uint bump_state_offset
Definition scene/svm.h:230
void generate_node(ShaderNode *node, ShaderNodeSet &done)
Definition svm.cpp:444
int stack_assign_if_linked(ShaderInput *input)
Definition svm.cpp:302
Shader * current_shader
Definition scene/svm.h:226
void stack_clear_users(ShaderNode *node, ShaderNodeSet &done)
Definition svm.cpp:336
int stack_size(SocketType::Type type)
Definition svm.cpp:173
void stack_clear_temporary(ShaderNode *node)
Definition svm.cpp:368
uint encode_uchar4(uint x, uint y=0, uint z=0, uint w=0)
Definition svm.cpp:378
uint attribute_standard(ustring name)
Definition svm.cpp:422
Stack active_stack
Definition scene/svm.h:227
void stack_link(ShaderInput *input, ShaderOutput *output)
Definition svm.cpp:320
void find_dependencies(ShaderNodeSet &dependencies, const ShaderNodeSet &done, ShaderInput *input, ShaderNode *skip_node=NULL)
Definition svm.cpp:428
void generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state)
Definition svm.cpp:468
bool is_linked(ShaderInput *input)
Definition svm.cpp:297
void generate_multi_closure(ShaderNode *root_node, ShaderNode *node, CompilerState *state)
Definition svm.cpp:586
uint attribute(ustring name)
Definition svm.cpp:412
std::atomic_int * svm_node_types_used
Definition scene/svm.h:223
uint mix_weight_offset
Definition scene/svm.h:229
bool compile_failed
Definition scene/svm.h:231
int stack_find_offset(int size)
Definition svm.cpp:199
void compile(Shader *shader, array< int4 > &svm_nodes, int index, Summary *summary=NULL)
Definition svm.cpp:870
void generated_shared_closure_nodes(ShaderNode *root_node, ShaderNode *node, CompilerState *state, const ShaderNodeSet &shared)
Definition svm.cpp:550
int stack_assign(ShaderOutput *output)
Definition svm.cpp:287
void reset(Scene *scene) override
Definition svm.cpp:30
void device_free(Device *device, DeviceScene *dscene, Scene *scene) override
Definition svm.cpp:149
~SVMShaderManager()
Definition svm.cpp:28
void device_update_specific(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress) override
Definition svm.cpp:52
void device_update_shader(Scene *scene, Shader *shader, Progress *progress, array< int4 > *svm_nodes)
Definition svm.cpp:32
ShaderOutput * link
const SocketType & socket_type
bool need_update() const
void device_free_common(Device *device, DeviceScene *dscene, Scene *scene)
vector< ShaderInput * > inputs
ShaderOutput * output(const char *name)
ShaderNode * parent
bool has_surface_spatial_varying
bool has_surface_bssrdf
bool has_volume_attribute_dependency
bool has_surface
bool has_bssrdf_bump
bool has_surface_raytrace
bool has_bump
bool has_surface_transparent
bool has_volume_spatial_varying
void append(const array< T > &from)
size_t size() const
void push_back_slow(const T &t)
local_group_size(16, 16) .push_constant(Type b
OperationNode * node
Depsgraph * graph
#define function_bind
#define CCL_NAMESPACE_END
#define NULL
#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 SVM_STACK_SIZE
ShaderNodeType
@ SHADER_TYPE_BUMP
@ SHADER_TYPE_SURFACE
@ SHADER_TYPE_VOLUME
@ SHADER_TYPE_DISPLACEMENT
#define SVM_BUMP_EVAL_STATE_SIZE
#define SVM_STACK_INVALID
#define KERNEL_FEATURE_NODE_MASK_DISPLACEMENT
AttributeStandard
#define KERNEL_FEATURE_NODE_MASK_BUMP
@ EMISSION_SAMPLING_NONE
#define KERNEL_FEATURE_NODE_MASK_VOLUME
#define KERNEL_FEATURE_NODE_MASK_SURFACE
#define KERNEL_FEATURE_NODE_RAYTRACE
#define VLOG_INFO
Definition log.h:72
#define VLOG_WORK
Definition log.h:75
static ulong state[N]
@ DISPLACE_TRUE
@ 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
ustring name
Definition graph/node.h:177
void clear_modified()
CompilerState(ShaderGraph *graph)
Definition svm.cpp:987
int users[SVM_STACK_SIZE]
Definition scene/svm.h:163
double time_generate_volume
Definition scene/svm.h:73
double time_generate_surface
Definition scene/svm.h:67
double time_generate_bump
Definition scene/svm.h:70
string full_report() const
Definition svm.cpp:965
double time_generate_displacement
Definition scene/svm.h:76
void push(TaskRunFunction &&task)
Definition task.cpp:22
void wait_work(Summary *stats=NULL)
Definition task.cpp:28
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
CCL_NAMESPACE_BEGIN double time_dt()
Definition time.cpp:36
float max
wmTimer * timer