Blender V5.0
gpu_node_graph.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cstdio>
12#include <cstring>
13
14#include "MEM_guardedalloc.h"
15
16#include "DNA_node_types.h"
17
18#include "BLI_ghash.h"
19#include "BLI_listbase.h"
20#include "BLI_stack.hh"
21#include "BLI_string.h"
22#include "BLI_utildefines.h"
23
24#include "GPU_texture.hh"
25#include "GPU_vertex_format.hh"
26
28#include "gpu_node_graph.hh"
29
30/* Node Link Functions */
31
33{
34 GPUNodeLink *link = MEM_callocN<GPUNodeLink>("GPUNodeLink");
35 link->users++;
36
37 return link;
38}
39
41{
42 link->users--;
43
44 if (link->users < 0) {
45 fprintf(stderr, "gpu_node_link_free: negative refcount\n");
46 }
47
48 if (link->users == 0) {
49 if (link->output) {
50 link->output->link = nullptr;
51 }
52 MEM_freeN(link);
53 }
54}
55
56/* Node Functions */
57
58static GPUNode *gpu_node_create(const char *name)
59{
60 GPUNode *node = MEM_callocN<GPUNode>("GPUNode");
61
62 node->name = name;
63 node->zone_index = -1;
64 node->is_zone_end = false;
65
66 return node;
67}
68
69static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType type)
70{
72 GPUNode *outnode;
73 const char *name;
74
75 if (link->link_type == GPU_NODE_LINK_OUTPUT) {
76 outnode = link->output->node;
77 name = outnode->name;
78 input = static_cast<GPUInput *>(outnode->inputs.first);
79
80 if (STR_ELEM(name, "set_value", "set_rgb", "set_rgba") && (input->type == type)) {
81 input = static_cast<GPUInput *>(MEM_dupallocN(outnode->inputs.first));
82
83 switch (input->source) {
84 case GPU_SOURCE_ATTR:
85 input->attr->users++;
86 break;
88 input->uniform_attr->users++;
89 break;
91 input->layer_attr->users++;
92 break;
93 case GPU_SOURCE_TEX:
94 input->texture->users++;
95 break;
97 /* Already handled by GPU_SOURCE_TEX. */
98 default:
99 break;
100 }
101
102 if (input->link) {
103 input->link->users++;
104 }
105
106 BLI_addtail(&node->inputs, input);
107 return;
108 }
109 }
110
111 input = MEM_callocN<GPUInput>("GPUInput");
112 input->node = node;
113 input->type = type;
114
115 switch (link->link_type) {
117 input->source = GPU_SOURCE_OUTPUT;
118 input->link = link;
119 link->users++;
120 break;
125 input->source = GPU_SOURCE_TEX;
126 input->texture = link->texture;
127 break;
130 input->texture = link->texture;
131 break;
133 input->source = GPU_SOURCE_ATTR;
134 input->attr = link->attr;
135 /* Fail-safe handling if the same attribute is used with different data-types for
136 * some reason (only really makes sense with float/vec2/vec3/vec4 though). This
137 * can happen if mixing the generic Attribute node with specialized ones. */
138 CLAMP_MIN(input->attr->gputype, type);
139 break;
142 input->uniform_attr = link->uniform_attr;
143 break;
146 input->layer_attr = link->layer_attr;
147 break;
150 break;
152 input->source = GPU_SOURCE_UNIFORM;
153 break;
156 /* NOTE(@fclem): End of function call is the return variable set during codegen. */
157 SNPRINTF(input->function_call,
158 "dF_branch_incomplete(%s(), %g, ",
161 break;
162 default:
163 break;
164 }
165
167 memcpy(input->vec, link->data, type * sizeof(float));
168 }
169
170 if (link->link_type != GPU_NODE_LINK_OUTPUT) {
171 MEM_freeN(link);
172 }
173 BLI_addtail(&node->inputs, input);
174}
175
177{
178 switch (type) {
179 /* For now INT & BOOL are supported as float. */
180 case SOCK_INT:
181 case SOCK_FLOAT:
182 case SOCK_BOOLEAN:
183 return "set_value";
184 case SOCK_VECTOR:
185 return "set_rgb";
186 case SOCK_RGBA:
187 return "set_rgba";
188 default:
189 BLI_assert_msg(0, "No gpu function for non-supported eNodeSocketDatatype");
190 return nullptr;
191 }
192}
193
199 const bNode *node,
200 GPUNodeStack *stack,
201 const int index,
202 const eNodeSocketInOut in_out)
203{
204 bNodeSocket *socket;
205
206 if (in_out == SOCK_IN) {
207 socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, index));
208 }
209 else {
210 socket = static_cast<bNodeSocket *>(BLI_findlink(&node->outputs, index));
211 }
212
213 BLI_assert(socket != nullptr);
214 BLI_assert(socket->in_out == in_out);
215
216 if (socket->flag & SOCK_HIDE_VALUE) {
217 return nullptr;
218 }
219
220 if (!ELEM(socket->type, SOCK_INT, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA)) {
221 return nullptr;
222 }
223
224 GPUNodeLink *link = GPU_uniform(stack->vec);
225
226 if (in_out == SOCK_IN) {
227 GPU_link(mat,
229 link,
230 &stack->link);
231 }
232
233 return link;
234}
235
237 GPUMaterial *material, const bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index)
238{
239 if (sock->link) {
240 gpu_node_input_link(node, sock->link, sock->type);
241 }
242 else if ((material != nullptr) &&
243 (gpu_uniformbuffer_link(material, bnode, sock, index, SOCK_IN) != nullptr))
244 {
245 gpu_node_input_link(node, sock->link, sock->type);
246 }
247 else {
248 gpu_node_input_link(node, GPU_constant(sock->vec), sock->type);
249 }
250}
251
252static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **link)
253{
255
256 output->type = type;
257 output->node = node;
258
259 if (link) {
260 *link = output->link = gpu_node_link_create();
261 output->link->link_type = GPU_NODE_LINK_OUTPUT;
262 output->link->output = output;
263
264 /* NOTE: the caller owns the reference to the link, GPUOutput
265 * merely points to it, and if the node is destroyed it will
266 * set that pointer to nullptr */
267 }
268
269 BLI_addtail(&node->outputs, output);
270}
271
272/* Uniform Attribute Functions */
273
274static int uniform_attr_sort_cmp(const void *a, const void *b)
275{
276 const GPUUniformAttr *attr_a = static_cast<const GPUUniformAttr *>(a),
277 *attr_b = static_cast<const GPUUniformAttr *>(b);
278
279 int cmps = strcmp(attr_a->name, attr_b->name);
280 if (cmps != 0) {
281 return cmps > 0 ? 1 : 0;
282 }
283
284 return (attr_a->use_dupli && !attr_b->use_dupli);
285}
286
287static uint uniform_attr_list_hash(const void *key)
288{
289 const GPUUniformAttrList *attrs = static_cast<const GPUUniformAttrList *>(key);
290 return attrs->hash_code;
291}
292
293static bool uniform_attr_list_cmp(const void *a, const void *b)
294{
295 const GPUUniformAttrList *set_a = static_cast<const GPUUniformAttrList *>(a),
296 *set_b = static_cast<const GPUUniformAttrList *>(b);
297
298 if (set_a->hash_code != set_b->hash_code || set_a->count != set_b->count) {
299 return true;
300 }
301
302 GPUUniformAttr *attr_a = static_cast<GPUUniformAttr *>(set_a->list.first),
303 *attr_b = static_cast<GPUUniformAttr *>(set_b->list.first);
304
305 for (; attr_a && attr_b; attr_a = attr_a->next, attr_b = attr_b->next) {
306 if (!STREQ(attr_a->name, attr_b->name) || attr_a->use_dupli != attr_b->use_dupli) {
307 return true;
308 }
309 }
310
311 return attr_a || attr_b;
312}
313
318
320{
321 dest->count = src->count;
322 dest->hash_code = src->hash_code;
323 BLI_duplicatelist(&dest->list, &src->list);
324}
325
327{
328 set->count = 0;
329 set->hash_code = 0;
330 BLI_freelistN(&set->list);
331}
332
334{
335 GPUUniformAttrList *attrs = &graph->uniform_attrs;
336 BLI_assert(attrs->count == BLI_listbase_count(&attrs->list));
337
338 /* Sort the attributes by name to ensure a stable order. */
340
341 /* Compute the indices and the hash code. */
342 int next_id = 0;
343 attrs->hash_code = 0;
344
345 LISTBASE_FOREACH (GPUUniformAttr *, attr, &attrs->list) {
346 attr->id = next_id++;
347 attrs->hash_code ^= BLI_ghashutil_uinthash(attr->hash_code + (1 << (attr->id + 1)));
348 }
349}
350
351/* Attributes and Textures */
352
353static char attr_prefix_get(const GPUMaterialAttribute *attr)
354{
355 if (attr->is_default_color) {
356 return 'c';
357 }
358 if (attr->is_hair_length) {
359 return 'l';
360 }
361 if (attr->is_hair_intercept) {
362 return 'i';
363 }
364 switch (attr->type) {
365 case CD_TANGENT:
366 return 't';
368 return 'a';
369 default:
370 BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!");
371 return '\0';
372 }
373}
374
376{
377 /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.cc */
378 if (attr->type == CD_ORCO) {
379 /* OPTI: orco is computed from local positions, but only if no modifier is present. */
380 STRNCPY(attr->input_name, "orco");
381 }
382 else {
383 attr->input_name[0] = attr_prefix_get(attr);
384 attr->input_name[1] = '\0';
385 if (attr->name[0] != '\0') {
386 /* XXX FIXME: see notes in mesh_render_data_create() */
388 }
389 }
390}
391
394 eCustomDataType type,
395 const char *name,
396 const bool is_default_color,
397 const bool is_hair_length,
398 const bool is_hair_intercept)
399{
400 /* Find existing attribute. */
401 int num_attributes = 0;
402 GPUMaterialAttribute *attr = static_cast<GPUMaterialAttribute *>(graph->attributes.first);
403 for (; attr; attr = attr->next) {
404 if (attr->type == type && STREQ(attr->name, name) &&
405 attr->is_default_color == is_default_color && attr->is_hair_length == is_hair_length &&
406 attr->is_hair_intercept == is_hair_intercept)
407 {
408 break;
409 }
410 num_attributes++;
411 }
412
413 /* Add new requested attribute if it's within GPU limits. */
414 if (attr == nullptr) {
415 attr = MEM_callocN<GPUMaterialAttribute>(__func__);
416 attr->is_default_color = is_default_color;
417 attr->is_hair_length = is_hair_length;
418 attr->is_hair_intercept = is_hair_intercept;
419 attr->type = type;
420 STRNCPY(attr->name, name);
421 attr_input_name(attr);
422 attr->id = num_attributes;
423 BLI_addtail(&graph->attributes, attr);
424 }
425
426 if (attr != nullptr) {
427 attr->users++;
428 }
429
430 return attr;
431}
432
435 const char *name,
436 bool use_dupli)
437{
438 /* Find existing attribute. */
439 GPUUniformAttrList *attrs = &graph->uniform_attrs;
440 GPUUniformAttr *attr = static_cast<GPUUniformAttr *>(attrs->list.first);
441
442 for (; attr; attr = attr->next) {
443 if (STREQ(attr->name, name) && attr->use_dupli == use_dupli) {
444 break;
445 }
446 }
447
448 /* Add new requested attribute if it's within GPU limits. */
449 if (attr == nullptr && attrs->count < GPU_MAX_UNIFORM_ATTR) {
450 attr = MEM_callocN<GPUUniformAttr>(__func__);
451 STRNCPY(attr->name, name);
452 attr->use_dupli = use_dupli;
453 attr->hash_code = BLI_ghashutil_strhash_p(attr->name) << 1 | (attr->use_dupli ? 0 : 1);
454 attr->id = -1;
455 BLI_addtail(&attrs->list, attr);
456 attrs->count++;
457 }
458
459 if (attr != nullptr) {
460 attr->users++;
461 }
462
463 return attr;
464}
465
468{
469 /* Find existing attribute. */
470 ListBase *attrs = &graph->layer_attrs;
471 GPULayerAttr *attr = static_cast<GPULayerAttr *>(attrs->first);
472
473 for (; attr; attr = attr->next) {
474 if (STREQ(attr->name, name)) {
475 break;
476 }
477 }
478
479 /* Add new requested attribute to the list. */
480 if (attr == nullptr) {
481 attr = MEM_callocN<GPULayerAttr>(__func__);
482 STRNCPY(attr->name, name);
484 BLI_addtail(attrs, attr);
485 }
486
487 if (attr != nullptr) {
488 attr->users++;
489 }
490
491 return attr;
492}
493
495 Image *ima,
496 ImageUser *iuser,
497 blender::gpu::Texture **colorband,
499 bool is_tiled,
500 GPUSamplerState sampler_state)
501{
502 /* Find existing texture. */
503 int num_textures = 0;
504 GPUMaterialTexture *tex = static_cast<GPUMaterialTexture *>(graph->textures.first);
505 for (; tex; tex = tex->next) {
506 if (tex->ima == ima && tex->colorband == colorband && tex->sky == sky &&
507 tex->sampler_state == sampler_state)
508 {
509 break;
510 }
511 num_textures++;
512 }
513
514 /* Add new requested texture. */
515 if (tex == nullptr) {
516 tex = MEM_callocN<GPUMaterialTexture>(__func__);
517 tex->ima = ima;
518 if (iuser != nullptr) {
519 tex->iuser = *iuser;
520 tex->iuser_available = true;
521 }
522 tex->colorband = colorband;
523 tex->sky = sky;
524 tex->sampler_state = sampler_state;
525 SNPRINTF(tex->sampler_name, "samp%d", num_textures);
526 if (is_tiled) {
527 SNPRINTF(tex->tiled_mapping_name, "tsamp%d", num_textures);
528 }
529 BLI_addtail(&graph->textures, tex);
530 }
531
532 tex->users++;
533
534 return tex;
535}
536
537/* Creating Inputs */
538
540{
543 graph, type, name, false, false, false);
544
545 if (type == CD_ORCO) {
546 /* OPTI: orco might be computed from local positions and needs object information. */
548 }
549
550 /* Dummy fallback if out of slots. */
551 if (attr == nullptr) {
552 static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
553 return GPU_constant(zero_data);
554 }
555
558 link->attr = attr;
559 return link;
560}
561
563{
566 graph, CD_AUTO_FROM_NAME, "", true, false, false);
567 if (attr == nullptr) {
568 static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
569 return GPU_constant(zero_data);
570 }
571 attr->is_default_color = true;
574 link->attr = attr;
575 return link;
576}
577
579{
582 graph, CD_AUTO_FROM_NAME, "", false, true, false);
583 if (attr == nullptr) {
584 static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
585 return GPU_constant(zero_data);
586 }
589 link->attr = attr;
590 return link;
591}
592
594{
597 graph, CD_AUTO_FROM_NAME, "", false, false, true);
598 if (attr == nullptr) {
599 static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
600 return GPU_constant(zero_data);
601 }
604 link->attr = attr;
605 return link;
606}
607
609 const eCustomDataType type,
610 const char *name,
611 GPUDefaultValue default_value)
612{
613 GPUNodeLink *link = GPU_attribute(mat, type, name);
614 if (link->link_type == GPU_NODE_LINK_ATTR) {
615 link->attr->default_value = default_value;
616 }
617 return link;
618}
619
621 const char *name,
622 bool use_dupli,
623 uint32_t *r_hash)
624{
627
628 /* Dummy fallback if out of slots. */
629 if (attr == nullptr) {
630 *r_hash = 0;
631 static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
632 return GPU_constant(zero_data);
633 }
634 *r_hash = attr->hash_code;
635
638 link->uniform_attr = attr;
639 return link;
640}
641
643{
646
649 link->layer_attr = attr;
650 return link;
651}
652
654{
657 link->data = num;
658 return link;
659}
660
662{
665 link->data = num;
666 return link;
667}
668
669GPUNodeLink *GPU_differentiate_float_function(const char *function_name, const float filter_width)
670{
673 link->differentiate_float.function_name = function_name;
674 link->differentiate_float.filter_width = filter_width;
675 return link;
676}
677
679 Image *ima,
680 ImageUser *iuser,
681 GPUSamplerState sampler_state)
682{
687 graph, ima, iuser, nullptr, nullptr, false, sampler_state);
688 return link;
689}
690
692 int width,
693 int height,
694 const float *pixels,
695 float *layer,
696 GPUSamplerState sampler_state)
697{
699 mat, width, height, pixels, layer);
700
705 graph, nullptr, nullptr, nullptr, sky, false, sampler_state);
706 return link;
707}
708
710 Image *ima,
711 ImageUser *iuser,
712 GPUSamplerState sampler_state,
713 GPUNodeLink **r_image_tiled_link,
714 GPUNodeLink **r_image_tiled_mapping_link)
715{
718 graph, ima, iuser, nullptr, nullptr, true, sampler_state);
719
720 (*r_image_tiled_link) = gpu_node_link_create();
721 (*r_image_tiled_link)->link_type = GPU_NODE_LINK_IMAGE_TILED;
722 (*r_image_tiled_link)->texture = texture;
723
724 (*r_image_tiled_mapping_link) = gpu_node_link_create();
725 (*r_image_tiled_mapping_link)->link_type = GPU_NODE_LINK_IMAGE_TILED_MAPPING;
726 (*r_image_tiled_mapping_link)->texture = texture;
727}
728
729GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *r_row)
730{
731 blender::gpu::Texture **colorband = gpu_material_ramp_texture_row_set(mat, size, pixels, r_row);
732 MEM_freeN(pixels);
733
738 graph, nullptr, nullptr, colorband, nullptr, false, GPUSamplerState::internal_sampler());
739 return link;
740}
741
742/* Creating Nodes */
743
744bool GPU_link(GPUMaterial *mat, const char *name, ...)
745{
747 GPUNode *node;
748 GPUFunction *function;
749 GPUNodeLink *link, **linkptr;
750 va_list params;
751 int i;
752
754 if (!function) {
755 fprintf(stderr, "GPU failed to find function %s\n", name);
756 return false;
757 }
758
759 node = gpu_node_create(name);
760
761 va_start(params, name);
762 for (i = 0; i < function->totparam; i++) {
763 if (function->paramqual[i] == FUNCTION_QUAL_OUT) {
764 linkptr = va_arg(params, GPUNodeLink **);
765 gpu_node_output(node, function->paramtype[i], linkptr);
766 }
767 else {
768 link = va_arg(params, GPUNodeLink *);
769 gpu_node_input_link(node, link, function->paramtype[i]);
770 }
771 }
772 va_end(params);
773
774 BLI_addtail(&graph->nodes, node);
775
776 return true;
777}
778
779static bool gpu_stack_link_v(GPUMaterial *material,
780 const bNode *bnode,
781 const char *name,
784 va_list params)
785{
786 GPUNodeGraph *graph = gpu_material_node_graph(material);
787 GPUNode *node;
788 GPUFunction *function;
789 GPUNodeLink *link, **linkptr;
790 int i, totin, totout;
791
793 if (!function) {
794 fprintf(stderr, "GPU failed to find function %s\n", name);
795 return false;
796 }
797
798 node = gpu_node_create(name);
799 totin = 0;
800 totout = 0;
801
802 if (in) {
803 for (i = 0; !in[i].end; i++) {
804 if (in[i].type != GPU_NONE) {
805 gpu_node_input_socket(material, bnode, node, &in[i], i);
806 totin++;
807 }
808 }
809 }
810
811 if (out) {
812 for (i = 0; !out[i].end; i++) {
813 if (out[i].type != GPU_NONE) {
814 gpu_node_output(node, out[i].type, &out[i].link);
815 totout++;
816 }
817 }
818 }
819
820 for (i = 0; i < function->totparam; i++) {
821 if (function->paramqual[i] == FUNCTION_QUAL_OUT) {
822 if (totout == 0) {
823 linkptr = va_arg(params, GPUNodeLink **);
824 gpu_node_output(node, function->paramtype[i], linkptr);
825 }
826 else {
827 totout--;
828 }
829 }
830 else {
831 if (totin == 0) {
832 link = va_arg(params, GPUNodeLink *);
833 if (link->socket) {
834 gpu_node_input_socket(nullptr, nullptr, node, link->socket, -1);
835 }
836 else {
837 gpu_node_input_link(node, link, function->paramtype[i]);
838 }
839 }
840 else {
841 totin--;
842 }
843 }
844 }
845
846 BLI_addtail(&graph->nodes, node);
847
848 return true;
849}
850
852 const bNode *bnode,
853 const char *name,
856 ...)
857{
858 va_list params;
859 va_start(params, out);
860 bool valid = gpu_stack_link_v(material, bnode, name, in, out, params);
861 va_end(params);
862
863 return valid;
864}
865
867 const bNode *bnode,
868 const char *name,
871 int zone_index,
872 bool is_zone_end,
873 int in_argument_count,
874 int out_argument_count)
875{
876 GPUNodeGraph *graph = gpu_material_node_graph(material);
877 GPUNode *node;
878 int i;
879
880 node = gpu_node_create(name);
881 node->zone_index = zone_index;
882 node->is_zone_end = is_zone_end;
883
884 if (in) {
885 for (i = 0; !in[i].end; i++) {
886 if (in[i].type != GPU_NONE) {
887 gpu_node_input_socket(material, bnode, node, &in[i], i);
888 }
889 }
890 }
891
892 if (out) {
893 for (i = 0; !out[i].end; i++) {
894 if (out[i].type != GPU_NONE) {
895 gpu_node_output(node, out[i].type, &out[i].link);
896 }
897 }
898 }
899
901 input->is_zone_io = i >= in_argument_count;
902 input->is_duplicate = input->is_zone_io && is_zone_end;
903 }
905 output->is_zone_io = i >= out_argument_count;
906 output->is_duplicate = output->is_zone_io;
907 }
908
909 BLI_addtail(&graph->nodes, node);
910
911 return true;
912}
913
914/* Node Graph */
915
917{
919 switch (input->source) {
920 case GPU_SOURCE_ATTR:
921 input->attr->users--;
922 break;
924 input->uniform_attr->users--;
925 break;
927 input->layer_attr->users--;
928 break;
929 case GPU_SOURCE_TEX:
930 input->texture->users--;
931 break;
933 /* Already handled by GPU_SOURCE_TEX. */
934 default:
935 break;
936 }
937
938 if (input->link) {
940 }
941 }
942
944}
945
946static void gpu_node_free(GPUNode *node)
947{
948 gpu_inputs_free(&node->inputs);
949
951 if (output->link) {
952 output->link->output = nullptr;
954 }
955 }
956
957 BLI_freelistN(&node->outputs);
958 MEM_freeN(node);
959}
960
962{
963 while (GPUNode *node = static_cast<GPUNode *>(BLI_pophead(&graph->nodes))) {
964 gpu_node_free(node);
965 }
966
967 graph->outlink_surface = nullptr;
968 graph->outlink_volume = nullptr;
969 graph->outlink_displacement = nullptr;
970 graph->outlink_thickness = nullptr;
971}
972
985
986/* Prune Unused Nodes */
987
988void gpu_nodes_tag(GPUNodeGraph *graph, GPUNodeLink *link_start, GPUNodeTag tag)
989{
990 if (!link_start || !link_start->output) {
991 return;
992 }
993
995 blender::Stack<GPUNode *> zone_stack;
996 stack.push(link_start->output->node);
997
998 while (!stack.is_empty() || !zone_stack.is_empty()) {
999 GPUNode *node = !stack.is_empty() ? stack.pop() : zone_stack.pop();
1000
1001 if (node->tag & tag) {
1002 continue;
1003 }
1004
1005 node->tag |= tag;
1006 LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
1007 if (input->link && input->link->output) {
1008 stack.push(input->link->output->node);
1009 }
1010 }
1011
1012 /* Zone input nodes are implicitly linked to their corresponding zone output nodes,
1013 * even if there is no GPUNodeLink between them. */
1014 if (node->is_zone_end) {
1015 LISTBASE_FOREACH (GPUNode *, node2, &graph->nodes) {
1016 if (node2->zone_index == node->zone_index && !node2->is_zone_end && !(node2->tag & tag)) {
1017 node2->tag |= tag;
1018 LISTBASE_FOREACH (GPUInput *, input, &node2->inputs) {
1019 if (input->link && input->link->output) {
1020 zone_stack.push(input->link->output->node);
1021 }
1022 }
1023 }
1024 }
1025 }
1026 }
1027}
1028
1030{
1031 LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
1032 node->tag = GPU_NODE_TAG_NONE;
1033 }
1034
1039
1041 gpu_nodes_tag(graph, aovlink->outlink, GPU_NODE_TAG_AOV);
1042 }
1044 gpu_nodes_tag(graph, funclink->outlink, GPU_NODE_TAG_FUNCTION);
1045 }
1046 LISTBASE_FOREACH (GPUNodeGraphOutputLink *, compositor_link, &graph->outlink_compositor) {
1047 gpu_nodes_tag(graph, compositor_link->outlink, GPU_NODE_TAG_COMPOSITOR);
1048 }
1049
1050 for (GPUNode *node = static_cast<GPUNode *>(graph->nodes.first), *next = nullptr; node;
1051 node = next)
1052 {
1053 next = node->next;
1054
1055 if (node->tag == GPU_NODE_TAG_NONE) {
1056 BLI_remlink(&graph->nodes, node);
1057 gpu_node_free(node);
1058 }
1059 }
1060
1061 for (GPUMaterialAttribute *attr = static_cast<GPUMaterialAttribute *>(graph->attributes.first),
1062 *next = nullptr;
1063 attr;
1064 attr = next)
1065 {
1066 next = attr->next;
1067 if (attr->users == 0) {
1068 BLI_freelinkN(&graph->attributes, attr);
1069 }
1070 }
1071
1072 for (GPUMaterialTexture *tex = static_cast<GPUMaterialTexture *>(graph->textures.first),
1073 *next = nullptr;
1074 tex;
1075 tex = next)
1076 {
1077 next = tex->next;
1078 if (tex->users == 0) {
1079 BLI_freelinkN(&graph->textures, tex);
1080 }
1081 }
1082
1083 GPUUniformAttrList *uattrs = &graph->uniform_attrs;
1084
1085 LISTBASE_FOREACH_MUTABLE (GPUUniformAttr *, attr, &uattrs->list) {
1086 if (attr->users == 0) {
1087 BLI_freelinkN(&uattrs->list, attr);
1088 uattrs->count--;
1089 }
1090 }
1091
1093 if (attr->users == 0) {
1094 BLI_freelinkN(&graph->layer_attrs, attr);
1095 }
1096 }
1097}
1098
1100{
1101 /* Replace all uniform node links with constant. */
1102 LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
1103 LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
1104 if (input->link) {
1105 if (input->link->link_type == GPU_NODE_LINK_UNIFORM) {
1106 input->link->link_type = GPU_NODE_LINK_CONSTANT;
1107 }
1108 }
1109 if (input->source == GPU_SOURCE_UNIFORM) {
1111 }
1112 }
1113 }
1114
1115 /* TODO: Consider performing other node graph optimizations here. */
1116}
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
unsigned int BLI_ghashutil_uinthash(unsigned int key)
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:686
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void void BLI_listbase_sort(ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void void void void void BLI_duplicatelist(ListBase *dst, const ListBase *src) ATTR_NONNULL(1
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:252
ATTR_WARN_UNUSED_RESULT const size_t num
#define STR_ELEM(...)
Definition BLI_string.h:661
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned int uint
#define ELEM(...)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
@ CD_AUTO_FROM_NAME
eNodeSocketInOut
@ SOCK_IN
@ SOCK_HIDE_VALUE
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_FLOAT
@ SOCK_RGBA
GPUDefaultValue
GPUType
@ GPU_MAX_CONSTANT_DATA
@ GPU_NONE
@ GPU_CLOSURE
@ GPU_MATFLAG_OBJECT_INFO
void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag)
static constexpr int GPU_MAX_UNIFORM_ATTR
Definition GPU_shader.hh:36
void GPU_vertformat_safe_attr_name(blender::StringRef attr_name, char *r_safe_name, uint max_len)
static constexpr int GPU_MAX_SAFE_ATTR_NAME
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
bool is_empty() const
Definition BLI_stack.hh:308
void push(const T &value)
Definition BLI_stack.hh:213
blender::gpu::Texture ** gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, const float *pixels, float *r_row)
blender::gpu::Texture ** gpu_material_sky_texture_layer_set(GPUMaterial *mat, int width, int height, const float *pixels, float *row)
GPUNodeGraph * gpu_material_node_graph(GPUMaterial *material)
@ FUNCTION_QUAL_OUT
GPUFunction * gpu_material_library_get_function(const char *name)
GPUNodeLink * GPU_constant(const float *num)
GPUNodeLink * GPU_attribute_hair_length(GPUMaterial *mat)
static GPUNodeLink * gpu_node_link_create()
static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType type)
GPUNodeLink * GPU_layer_attribute(GPUMaterial *mat, const char *name)
GPUNodeLink * GPU_attribute_default_color(GPUMaterial *mat)
bool GPU_stack_link(GPUMaterial *material, const bNode *bnode, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
GPUNodeLink * GPU_attribute_with_default(GPUMaterial *mat, const eCustomDataType type, const char *name, GPUDefaultValue default_value)
static GPUNode * gpu_node_create(const char *name)
static void gpu_node_free(GPUNode *node)
static void gpu_inputs_free(ListBase *inputs)
static GPUMaterialAttribute * gpu_node_graph_add_attribute(GPUNodeGraph *graph, eCustomDataType type, const char *name, const bool is_default_color, const bool is_hair_length, const bool is_hair_intercept)
GPUNodeLink * GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *r_row)
static void gpu_node_input_socket(GPUMaterial *material, const bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index)
void gpu_nodes_tag(GPUNodeGraph *graph, GPUNodeLink *link_start, GPUNodeTag tag)
static GPULayerAttr * gpu_node_graph_add_layer_attribute(GPUNodeGraph *graph, const char *name)
static GPUUniformAttr * gpu_node_graph_add_uniform_attribute(GPUNodeGraph *graph, const char *name, bool use_dupli)
void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph)
static void gpu_node_link_free(GPUNodeLink *link)
GPUNodeLink * GPU_attribute(GPUMaterial *mat, const eCustomDataType type, const char *name)
void gpu_node_graph_optimize(GPUNodeGraph *graph)
static GPUMaterialTexture * gpu_node_graph_add_texture(GPUNodeGraph *graph, Image *ima, ImageUser *iuser, blender::gpu::Texture **colorband, blender::gpu::Texture **sky, bool is_tiled, GPUSamplerState sampler_state)
GPUNodeLink * GPU_image(GPUMaterial *mat, Image *ima, ImageUser *iuser, GPUSamplerState sampler_state)
void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, const GPUUniformAttrList *src)
static uint uniform_attr_list_hash(const void *key)
GHash * GPU_uniform_attr_list_hash_new(const char *info)
void GPU_uniform_attr_list_free(GPUUniformAttrList *set)
GPUNodeLink * GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli, uint32_t *r_hash)
GPUNodeLink * GPU_image_sky(GPUMaterial *mat, int width, int height, const float *pixels, float *layer, GPUSamplerState sampler_state)
bool GPU_stack_link_zone(GPUMaterial *material, const bNode *bnode, const char *name, GPUNodeStack *in, GPUNodeStack *out, int zone_index, bool is_zone_end, int in_argument_count, int out_argument_count)
void gpu_node_graph_free(GPUNodeGraph *graph)
void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
void GPU_image_tiled(GPUMaterial *mat, Image *ima, ImageUser *iuser, GPUSamplerState sampler_state, GPUNodeLink **r_image_tiled_link, GPUNodeLink **r_image_tiled_mapping_link)
static void attr_input_name(GPUMaterialAttribute *attr)
static char attr_prefix_get(const GPUMaterialAttribute *attr)
static bool uniform_attr_list_cmp(const void *a, const void *b)
GPUNodeLink * GPU_differentiate_float_function(const char *function_name, const float filter_width)
GPUNodeLink * GPU_attribute_hair_intercept(GPUMaterial *mat)
static bool gpu_stack_link_v(GPUMaterial *material, const bNode *bnode, const char *name, GPUNodeStack *in, GPUNodeStack *out, va_list params)
static int uniform_attr_sort_cmp(const void *a, const void *b)
static const char * gpu_uniform_set_function_from_type(eNodeSocketDatatype type)
void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
static GPUNodeLink * gpu_uniformbuffer_link(GPUMaterial *mat, const bNode *node, GPUNodeStack *stack, const int index, const eNodeSocketInOut in_out)
bool GPU_link(GPUMaterial *mat, const char *name,...)
static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **link)
GPUNodeLink * GPU_uniform(const float *num)
@ GPU_SOURCE_CONSTANT
@ GPU_SOURCE_FUNCTION_CALL
@ GPU_SOURCE_ATTR
@ GPU_SOURCE_UNIFORM
@ GPU_SOURCE_OUTPUT
@ GPU_SOURCE_TEX_TILED_MAPPING
@ GPU_SOURCE_UNIFORM_ATTR
@ GPU_SOURCE_LAYER_ATTR
@ GPU_SOURCE_STRUCT
@ GPU_SOURCE_TEX
GPUNodeTag
@ GPU_NODE_TAG_NONE
@ GPU_NODE_TAG_SURFACE
@ GPU_NODE_TAG_DISPLACEMENT
@ GPU_NODE_TAG_VOLUME
@ GPU_NODE_TAG_FUNCTION
@ GPU_NODE_TAG_COMPOSITOR
@ GPU_NODE_TAG_THICKNESS
@ GPU_NODE_TAG_AOV
@ GPU_NODE_LINK_UNIFORM
@ GPU_NODE_LINK_IMAGE_SKY
@ GPU_NODE_LINK_LAYER_ATTR
@ GPU_NODE_LINK_ATTR
@ GPU_NODE_LINK_IMAGE
@ GPU_NODE_LINK_IMAGE_TILED
@ GPU_NODE_LINK_CONSTANT
@ GPU_NODE_LINK_IMAGE_TILED_MAPPING
@ GPU_NODE_LINK_COLORBAND
@ GPU_NODE_LINK_UNIFORM_ATTR
@ GPU_NODE_LINK_OUTPUT
@ GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN
#define input
#define in
#define out
#define output
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
static blender::bke::bNodeSocketTemplate inputs[]
const char * name
GPUType paramtype[MAX_PARAMETER]
GPUFunctionQual paramqual[MAX_PARAMETER]
char name[256]
GPULayerAttr * next
uint32_t hash_code
GPUMaterialAttribute * next
GPUDefaultValue default_value
blender::gpu::Texture ** sky
GPUSamplerState sampler_state
char tiled_mapping_name[32]
GPUMaterialTexture * next
blender::gpu::Texture ** colorband
ListBase outlink_compositor
GPUNodeLink * outlink_displacement
ListBase layer_attrs
ListBase outlink_aovs
GPUNodeLink * outlink_thickness
GPUNodeLink * outlink_volume
ListBase attributes
GPUNodeLink * outlink_surface
GPUUniformAttrList uniform_attrs
ListBase material_functions
GPUNodeLink * link
GPUNodeTag tag
ListBase outputs
ListBase inputs
const char * name
bool is_zone_end
GPUNodeLink * link
GPUNode * node
static constexpr GPUSamplerState internal_sampler()
unsigned int hash_code
GPUUniformAttr * next
void * first
ListBase inputs
ListBase outputs
i
Definition text_draw.cc:230