Blender V4.3
node_composite_image.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "BLI_linklist.h"
13#include "BLI_rect.h"
14#include "BLI_string.h"
15#include "BLI_utildefines.h"
16
17#include "BKE_context.hh"
18#include "BKE_global.hh"
19#include "BKE_image.hh"
20#include "BKE_lib_id.hh"
21#include "BKE_main.hh"
22#include "BKE_scene.hh"
23
25
26#include "DNA_image_types.h"
27#include "DNA_scene_types.h"
28#include "DNA_vec_types.h"
29
30#include "RE_engine.h"
31#include "RE_pipeline.h"
32
33#include "RNA_access.hh"
34
35#include "UI_interface.hh"
36#include "UI_resources.hh"
37
38#include "GPU_shader.hh"
39#include "GPU_texture.hh"
40
42#include "COM_node_operation.hh"
43#include "COM_utilities.hh"
44
45/* **************** IMAGE (and RenderResult, multi-layer image) ******************** */
46
48 {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
49 {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
50 {SOCK_FLOAT, N_(RE_PASSNAME_Z), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
51 {SOCK_VECTOR, N_(RE_PASSNAME_NORMAL), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
52 {SOCK_VECTOR, N_(RE_PASSNAME_UV), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
53 {SOCK_VECTOR, N_(RE_PASSNAME_VECTOR), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
54 {SOCK_VECTOR, N_(RE_PASSNAME_POSITION), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
55 {SOCK_RGBA, N_(RE_PASSNAME_DEPRECATED), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
56 {SOCK_RGBA, N_(RE_PASSNAME_DEPRECATED), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
57 {SOCK_RGBA, N_(RE_PASSNAME_SHADOW), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
58 {SOCK_RGBA, N_(RE_PASSNAME_AO), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
59 {SOCK_RGBA, N_(RE_PASSNAME_DEPRECATED), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
60 {SOCK_RGBA, N_(RE_PASSNAME_DEPRECATED), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
61 {SOCK_RGBA, N_(RE_PASSNAME_DEPRECATED), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
62 {SOCK_FLOAT, N_(RE_PASSNAME_INDEXOB), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
63 {SOCK_FLOAT, N_(RE_PASSNAME_INDEXMA), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
64 {SOCK_FLOAT, N_(RE_PASSNAME_MIST), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
65 {SOCK_RGBA, N_(RE_PASSNAME_EMIT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
66 {SOCK_RGBA, N_(RE_PASSNAME_ENVIRONMENT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
67 {SOCK_RGBA, N_(RE_PASSNAME_DIFFUSE_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
68 {SOCK_RGBA, N_(RE_PASSNAME_DIFFUSE_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
69 {SOCK_RGBA, N_(RE_PASSNAME_DIFFUSE_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
70 {SOCK_RGBA, N_(RE_PASSNAME_GLOSSY_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
71 {SOCK_RGBA, N_(RE_PASSNAME_GLOSSY_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
72 {SOCK_RGBA, N_(RE_PASSNAME_GLOSSY_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
73 {SOCK_RGBA, N_(RE_PASSNAME_TRANSM_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
74 {SOCK_RGBA, N_(RE_PASSNAME_TRANSM_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
75 {SOCK_RGBA, N_(RE_PASSNAME_TRANSM_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
76 {SOCK_RGBA, N_(RE_PASSNAME_SUBSURFACE_DIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
77 {SOCK_RGBA, N_(RE_PASSNAME_SUBSURFACE_INDIRECT), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
78 {SOCK_RGBA, N_(RE_PASSNAME_SUBSURFACE_COLOR), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
79 {-1, ""},
80};
81#define NUM_LEGACY_SOCKETS (ARRAY_SIZE(cmp_node_rlayers_out) - 1)
82
84 bNode *node,
85 const char *name,
86 const char *passname,
87 int rres_index,
89 int /*is_rlayers*/,
90 LinkNodePair *available_sockets,
91 int *prev_index)
92{
94 &node->outputs, name, offsetof(bNodeSocket, name));
95
96 /* Replace if types don't match. */
97 if (sock && sock->type != type) {
98 blender::bke::node_remove_socket(ntree, node, sock);
99 sock = nullptr;
100 }
101
102 /* Create socket if it doesn't exist yet. */
103 if (sock == nullptr) {
104 if (rres_index >= 0) {
106 ntree, node, &cmp_node_rlayers_out[rres_index], SOCK_OUT);
107 }
108 else {
110 ntree, node, SOCK_OUT, type, PROP_NONE, name, name);
111 }
112 /* extra socket info */
113 NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__);
114 sock->storage = sockdata;
115 }
116
117 NodeImageLayer *sockdata = (NodeImageLayer *)sock->storage;
118 if (sockdata) {
119 STRNCPY(sockdata->pass_name, passname);
120 }
121
122 /* Reorder sockets according to order that passes are added. */
123 const int after_index = (*prev_index)++;
124 bNodeSocket *after_sock = (bNodeSocket *)BLI_findlink(&node->outputs, after_index);
125 BLI_remlink(&node->outputs, sock);
126 BLI_insertlinkafter(&node->outputs, after_sock, sock);
127
128 BLI_linklist_append(available_sockets, sock);
129}
130
132 bNode *node,
133 LinkNodePair *available_sockets)
134{
135 Image *ima = (Image *)node->id;
136 ImBuf *ibuf;
137 int prev_index = -1;
138 if (ima) {
139 ImageUser *iuser = (ImageUser *)node->storage;
140 ImageUser load_iuser = {nullptr};
141 int offset = BKE_image_sequence_guess_offset(ima);
142
143 /* It is possible that image user in this node is not
144 * properly updated yet. In this case loading image will
145 * fail and sockets detection will go wrong.
146 *
147 * So we manually construct image user to be sure first
148 * image from sequence (that one which is set as filename
149 * for image data-block) is used for sockets detection. */
150 load_iuser.framenr = offset;
151
152 /* make sure ima->type is correct */
153 ibuf = BKE_image_acquire_ibuf(ima, &load_iuser, nullptr);
154
155 if (ima->rr) {
156 RenderLayer *rl = (RenderLayer *)BLI_findlink(&ima->rr->layers, iuser->layer);
157
158 if (rl) {
159 LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) {
161 if (rpass->channels == 1) {
162 type = SOCK_FLOAT;
163 }
164 else {
165 type = SOCK_RGBA;
166 }
167
169 node,
170 rpass->name,
171 rpass->name,
172 -1,
173 type,
174 false,
175 available_sockets,
176 &prev_index);
177 /* Special handling for the Combined pass to ensure compatibility. */
178 if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
180 node,
181 "Alpha",
182 rpass->name,
183 -1,
185 false,
186 available_sockets,
187 &prev_index);
188 }
189 }
190 BKE_image_release_ibuf(ima, ibuf, nullptr);
191 return;
192 }
193 }
194 }
195
197 node,
198 "Image",
200 -1,
201 SOCK_RGBA,
202 false,
203 available_sockets,
204 &prev_index);
206 node,
207 "Alpha",
209 -1,
211 false,
212 available_sockets,
213 &prev_index);
214
215 if (ima) {
216 BKE_image_release_ibuf(ima, ibuf, nullptr);
217 }
218}
219
224
226 bNode *node,
227 Scene *scene,
228 ViewLayer *view_layer,
229 const char *name,
231{
232 RLayerUpdateData *data = (RLayerUpdateData *)node->storage;
233
234 if (scene == nullptr || view_layer == nullptr || data == nullptr || node->id != (ID *)scene) {
235 return;
236 }
237
238 ViewLayer *node_view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, node->custom1);
239 if (node_view_layer != view_layer) {
240 return;
241 }
242
243 /* Special handling for the Combined pass to ensure compatibility. */
244 if (STREQ(name, RE_PASSNAME_COMBINED)) {
246 ntree, node, "Image", name, -1, type, true, data->available_sockets, &data->prev_index);
248 node,
249 "Alpha",
250 name,
251 -1,
253 true,
254 data->available_sockets,
255 &data->prev_index);
256 }
257 else {
259 ntree, node, name, name, -1, type, true, data->available_sockets, &data->prev_index);
260 }
261}
262
267
268static void cmp_node_rlayer_create_outputs_cb(void *userdata,
269 Scene *scene,
270 ViewLayer *view_layer,
271 const char *name,
272 int /*channels*/,
273 const char * /*chanid*/,
275{
276 CreateOutputUserData &data = *(CreateOutputUserData *)userdata;
277 node_cmp_rlayers_register_pass(&data.ntree, &data.node, scene, view_layer, name, type);
278}
279
281 bNode *node,
282 LinkNodePair *available_sockets)
283{
284 Scene *scene = (Scene *)node->id;
285
286 if (scene) {
287 RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
288 if (engine_type && engine_type->update_render_passes) {
289 ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, node->custom1);
290 if (view_layer) {
292 "render layer update data");
293 data->available_sockets = available_sockets;
294 data->prev_index = -1;
295 node->storage = data;
296
297 CreateOutputUserData userdata = {*ntree, *node};
298
299 RenderEngine *engine = RE_engine_create(engine_type);
301 engine, scene, view_layer, cmp_node_rlayer_create_outputs_cb, &userdata);
302 RE_engine_free(engine);
303
304 if ((scene->r.mode & R_EDGE_FRS) &&
306 {
308 ntree, node, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA);
309 }
310
311 MEM_freeN(data);
312 node->storage = nullptr;
313
314 return;
315 }
316 }
317 }
318
319 int prev_index = -1;
321 node,
322 "Image",
325 SOCK_RGBA,
326 true,
327 available_sockets,
328 &prev_index);
330 node,
331 "Alpha",
335 true,
336 available_sockets,
337 &prev_index);
338}
339
340/* XXX make this into a generic socket verification function for dynamic socket replacement
341 * (multi-layer, groups, static templates). */
342static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rlayer)
343{
344 bNodeSocket *sock, *sock_next;
345 LinkNodePair available_sockets = {nullptr, nullptr};
346
347 /* XXX make callback */
348 if (rlayer) {
349 cmp_node_rlayer_create_outputs(ntree, node, &available_sockets);
350 }
351 else {
352 cmp_node_image_create_outputs(ntree, node, &available_sockets);
353 }
354
355 /* Get rid of sockets whose passes are not available in the image.
356 * If sockets that are not available would be deleted, the connections to them would be lost
357 * when e.g. opening a file (since there's no render at all yet).
358 * Therefore, sockets with connected links will just be set as unavailable.
359 *
360 * Another important detail comes from compatibility with the older socket model, where there
361 * was a fixed socket per pass type that was just hidden or not. Therefore, older versions expect
362 * the first 31 passes to belong to a specific pass type.
363 * So, we keep those 31 always allocated before the others as well,
364 * even if they have no links attached. */
365 int sock_index = 0;
366 for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock_next, sock_index++) {
367 sock_next = sock->next;
368 if (BLI_linklist_index(available_sockets.list, sock) >= 0) {
369 sock->flag &= ~SOCK_HIDDEN;
371 }
372 else {
373 bNodeLink *link;
374 for (link = (bNodeLink *)ntree->links.first; link; link = link->next) {
375 if (link->fromsock == sock) {
376 break;
377 }
378 }
379 if (!link && (!rlayer || sock_index >= NUM_LEGACY_SOCKETS)) {
380 MEM_freeN(sock->storage);
381 blender::bke::node_remove_socket(ntree, node, sock);
382 }
383 else {
385 }
386 }
387 }
388
389 BLI_linklist_free(available_sockets.list, nullptr);
390}
391
393
394static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
395{
396 /* avoid unnecessary updates, only changes to the image/image user data are of interest */
397 if (node->runtime->update & NODE_UPDATE_ID) {
398 cmp_node_image_verify_outputs(ntree, node, false);
399 }
400
401 cmp_node_update_default(ntree, node);
402}
403
404static void node_composit_init_image(bNodeTree *ntree, bNode *node)
405{
406 ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
407 node->storage = iuser;
408 iuser->frames = 1;
409 iuser->sfra = 1;
410 iuser->flag |= IMA_ANIM_ALWAYS;
411
412 /* setup initial outputs */
413 cmp_node_image_verify_outputs(ntree, node, false);
414}
415
417{
418 /* free extra socket info */
419 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
420 MEM_freeN(sock->storage);
421 }
422
423 MEM_freeN(node->storage);
424}
425
426static void node_composit_copy_image(bNodeTree * /*dst_ntree*/,
427 bNode *dest_node,
428 const bNode *src_node)
429{
430 dest_node->storage = MEM_dupallocN(src_node->storage);
431
432 const bNodeSocket *src_output_sock = (bNodeSocket *)src_node->outputs.first;
433 bNodeSocket *dest_output_sock = (bNodeSocket *)dest_node->outputs.first;
434 while (dest_output_sock != nullptr) {
435 dest_output_sock->storage = MEM_dupallocN(src_output_sock->storage);
436
437 src_output_sock = src_output_sock->next;
438 dest_output_sock = dest_output_sock->next;
439 }
440}
441
442using namespace blender::realtime_compositor;
443
445 public:
447
448 void execute() override
449 {
450 for (const bNodeSocket *output : this->node()->output_sockets()) {
451 compute_output(output->identifier);
452 }
453 }
454
455 void compute_output(StringRef identifier)
456 {
457 if (!should_compute_output(identifier)) {
458 return;
459 }
460
461 Result *cached_image = context().cache_manager().cached_images.get(
462 context(), get_image(), get_image_user(), get_pass_name(identifier));
463
464 Result &result = get_result(identifier);
465 if (!cached_image || !cached_image->is_allocated()) {
466 result.allocate_invalid();
467 return;
468 }
469
470 /* Alpha is not an actual pass, but one that is extracted from the combined pass. */
471 if (identifier == "Alpha") {
472 extract_alpha(context(), *cached_image, result);
473 }
474 else {
475 cached_image->pass_through(result);
476 }
477 }
478
479 /* Get the name of the pass corresponding to the output with the given identifier. */
480 const char *get_pass_name(StringRef identifier)
481 {
482 DOutputSocket output = node().output_by_identifier(identifier);
483 return static_cast<NodeImageLayer *>(output->storage)->pass_name;
484 }
485
487 {
488 return reinterpret_cast<Image *>(bnode().id);
489 }
490
492 {
493 return static_cast<ImageUser *>(bnode().storage);
494 }
495};
496
498{
499 return new ImageOperation(context, node);
500}
501
502} // namespace blender::nodes::node_composite_image_cc
503
505{
506 namespace file_ns = blender::nodes::node_composite_image_cc;
507
508 static blender::bke::bNodeType ntype;
509
510 cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT);
511 ntype.initfunc = file_ns::node_composit_init_image;
513 &ntype, "ImageUser", file_ns::node_composit_free_image, file_ns::node_composit_copy_image);
514 ntype.updatefunc = file_ns::cmp_node_image_update;
515 ntype.get_compositor_operation = file_ns::get_compositor_operation;
517 ntype.flag |= NODE_PREVIEW;
518
520}
521
522/* **************** RENDER RESULT ******************** */
523
525{
526 cmp_node_image_verify_outputs(ntree, node, true);
527}
528
529const char *node_cmp_rlayers_sock_to_pass(int sock_index)
530{
531 if (sock_index >= NUM_LEGACY_SOCKETS) {
532 return nullptr;
533 }
534 const char *name = cmp_node_rlayers_out[sock_index].name;
535 /* Exception for alpha, which is derived from Combined. */
536 return STREQ(name, "Alpha") ? RE_PASSNAME_COMBINED : name;
537}
538
540
542{
543 Scene *scene = CTX_data_scene(C);
544 bNode *node = (bNode *)ptr->data;
545 int sock_index = 0;
546
547 node->id = &scene->id;
548 id_us_plus(node->id);
549
550 for (bNodeSocket *sock = (bNodeSocket *)node->outputs.first; sock;
551 sock = sock->next, sock_index++)
552 {
553 NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__);
554 sock->storage = sockdata;
555
556 STRNCPY(sockdata->pass_name, node_cmp_rlayers_sock_to_pass(sock_index));
557 }
558}
559
561 const bNodeTree *ntree,
562 const char **r_disabled_hint)
563{
564 if (!STREQ(ntree->idname, "CompositorNodeTree")) {
565 *r_disabled_hint = RPT_("Not a compositor node tree");
566 return false;
567 }
568
569 Scene *scene;
570
571 /* XXX ugly: check if ntree is a local scene node tree.
572 * Render layers node can only be used in local `scene->nodetree`,
573 * since it directly links to the scene.
574 */
575 for (scene = (Scene *)G.main->scenes.first; scene; scene = (Scene *)scene->id.next) {
576 if (scene->nodetree == ntree) {
577 break;
578 }
579 }
580
581 if (scene == nullptr) {
582 *r_disabled_hint = RPT_(
583 "The node tree must be the compositing node tree of any scene in the file");
584 return false;
585 }
586 return true;
587}
588
590{
591 /* free extra socket info */
592 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
593 if (sock->storage) {
594 MEM_freeN(sock->storage);
595 }
596 }
597}
598
599static void node_composit_copy_rlayers(bNodeTree * /*dst_ntree*/,
600 bNode *dest_node,
601 const bNode *src_node)
602{
603 /* copy extra socket info */
604 const bNodeSocket *src_output_sock = (bNodeSocket *)src_node->outputs.first;
605 bNodeSocket *dest_output_sock = (bNodeSocket *)dest_node->outputs.first;
606 while (dest_output_sock != nullptr) {
607 dest_output_sock->storage = MEM_dupallocN(src_output_sock->storage);
608
609 src_output_sock = src_output_sock->next;
610 dest_output_sock = dest_output_sock->next;
611 }
612}
613
614static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
615{
616 cmp_node_image_verify_outputs(ntree, node, true);
617
618 cmp_node_update_default(ntree, node);
619}
620
622{
623 bNode *node = (bNode *)ptr->data;
624 uiLayout *col, *row;
625
626 uiTemplateID(layout, C, ptr, "scene", nullptr, nullptr, nullptr);
627
628 if (!node->id) {
629 return;
630 }
631
632 col = uiLayoutColumn(layout, false);
633 row = uiLayoutRow(col, true);
634 uiItemR(row, ptr, "layer", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
635
636 PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
637 const char *layer_name;
638 if (!RNA_property_enum_identifier(C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name)) {
639 return;
640 }
641
642 PointerRNA scn_ptr;
643 char scene_name[MAX_ID_NAME - 2];
644 scn_ptr = RNA_pointer_get(ptr, "scene");
645 RNA_string_get(&scn_ptr, "name", scene_name);
646
647 PointerRNA op_ptr;
648 uiItemFullO(row,
649 "RENDER_OT_render",
650 "",
651 ICON_RENDER_STILL,
652 nullptr,
655 &op_ptr);
656 RNA_string_set(&op_ptr, "layer", layer_name);
657 RNA_string_set(&op_ptr, "scene", scene_name);
658}
659
660using namespace blender::realtime_compositor;
661
663 public:
665
666 void execute() override
667 {
668 const Scene *scene = reinterpret_cast<const Scene *>(bnode().id);
669 const int view_layer = bnode().custom1;
670
671 Result &image_result = get_result("Image");
672 Result &alpha_result = get_result("Alpha");
673
674 if (image_result.should_compute() || alpha_result.should_compute()) {
675 GPUTexture *combined_texture = context().get_input_texture(
676 scene, view_layer, RE_PASSNAME_COMBINED);
677 if (image_result.should_compute()) {
678 execute_pass(image_result, combined_texture, "compositor_read_input_color");
679 }
680 if (alpha_result.should_compute()) {
681 execute_pass(alpha_result, combined_texture, "compositor_read_input_alpha");
682 }
683 }
684
685 /* Other output passes are not supported for now, so allocate them as invalid. */
686 for (const bNodeSocket *output : this->node()->output_sockets()) {
687 if (STR_ELEM(output->identifier, "Image", "Alpha")) {
688 continue;
689 }
690
691 Result &result = get_result(output->identifier);
692 if (!result.should_compute()) {
693 continue;
694 }
695
697 scene, view_layer, output->identifier, result.meta_data);
698
699 GPUTexture *pass_texture = context().get_input_texture(
700 scene, view_layer, output->identifier);
701 if (output->type == SOCK_FLOAT) {
702 execute_pass(result, pass_texture, "compositor_read_input_float");
703 }
704 else if (output->type == SOCK_VECTOR) {
705 execute_pass(result, pass_texture, "compositor_read_input_vector");
706 }
707 else if (output->type == SOCK_RGBA) {
708 execute_pass(result, pass_texture, "compositor_read_input_color");
709 }
710 else {
712 }
713 }
714 }
715
716 void execute_pass(Result &result, GPUTexture *pass_texture, const char *shader_name)
717 {
718 if (pass_texture == nullptr) {
719 /* Pass not rendered yet, or not supported by viewport. */
720 result.allocate_invalid();
721 context().set_info_message("Viewport compositor setup not fully supported");
722 return;
723 }
724
725 if (!context().is_valid_compositing_region()) {
726 result.allocate_invalid();
727 return;
728 }
729
730 const ResultPrecision precision = Result::precision(GPU_texture_format(pass_texture));
731 GPUShader *shader = context().get_shader(shader_name, precision);
732 GPU_shader_bind(shader);
733
734 /* The compositing space might be limited to a subset of the pass texture, so only read that
735 * compositing region into an appropriately sized texture. */
736 const rcti compositing_region = context().get_compositing_region();
737 const int2 lower_bound = int2(compositing_region.xmin, compositing_region.ymin);
738 GPU_shader_uniform_2iv(shader, "lower_bound", lower_bound);
739
740 const int input_unit = GPU_shader_get_sampler_binding(shader, "input_tx");
741 GPU_texture_bind(pass_texture, input_unit);
742
743 result.set_precision(precision);
744
745 const int2 compositing_region_size = context().get_compositing_region_size();
746 result.allocate_texture(Domain(compositing_region_size));
747 result.bind_as_image(shader, "output_img");
748
749 compute_dispatch_threads_at_least(shader, compositing_region_size);
750
752 GPU_texture_unbind(pass_texture);
753 result.unbind_as_image();
754 }
755};
756
758{
759 return new RenderLayerOperation(context, node);
760}
761
762} // namespace blender::nodes::node_composite_render_layer_cc
763
765{
767
768 static blender::bke::bNodeType ntype;
769
770 cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT);
772 ntype.draw_buttons = file_ns::node_composit_buts_viewlayers;
773 ntype.initfunc_api = file_ns::node_composit_init_rlayers;
774 ntype.poll = file_ns::node_composit_poll_rlayers;
775 ntype.get_compositor_operation = file_ns::get_compositor_operation;
777 "Render passes not supported in the Viewport compositor");
778 ntype.flag |= NODE_PREVIEW;
780 &ntype, nullptr, file_ns::node_composit_free_rlayers, file_ns::node_composit_copy_rlayers);
781 ntype.updatefunc = file_ns::cmp_node_rlayers_update;
784
786}
Scene * CTX_data_scene(const bContext *C)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
int BKE_image_sequence_guess_offset(Image *image)
void id_us_plus(ID *id)
Definition lib_id.cc:351
#define RRES_OUT_ALPHA
Definition BKE_node.hh:1009
#define RRES_OUT_IMAGE
Definition BKE_node.hh:1008
#define NODE_CLASS_INPUT
Definition BKE_node.hh:404
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
#define STR_ELEM(...)
Definition BLI_string.h:653
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define STREQ(a, b)
#define RPT_(msgid)
#define MAX_ID_NAME
Definition DNA_ID.h:377
@ FREESTYLE_AS_RENDER_PASS
@ IMA_ANIM_ALWAYS
@ NODE_PREVIEW
@ NODE_UPDATE_ID
@ SOCK_OUT
eNodeSocketDatatype
@ SOCK_VECTOR
@ SOCK_FLOAT
@ SOCK_RGBA
#define RE_PASSNAME_COMBINED
#define RE_PASSNAME_UV
#define RE_PASSNAME_DIFFUSE_INDIRECT
#define RE_PASSNAME_INDEXMA
#define RE_PASSNAME_SUBSURFACE_DIRECT
#define RE_PASSNAME_NORMAL
#define RE_PASSNAME_TRANSM_DIRECT
#define RE_PASSNAME_VECTOR
#define RE_PASSNAME_TRANSM_COLOR
#define RE_PASSNAME_EMIT
#define RE_PASSNAME_SUBSURFACE_INDIRECT
#define RE_PASSNAME_GLOSSY_COLOR
#define RE_PASSNAME_SUBSURFACE_COLOR
#define RE_PASSNAME_TRANSM_INDIRECT
@ R_EDGE_FRS
#define RE_PASSNAME_GLOSSY_DIRECT
#define RE_PASSNAME_SHADOW
#define RE_PASSNAME_MIST
#define RE_PASSNAME_ENVIRONMENT
#define RE_PASSNAME_POSITION
#define RE_PASSNAME_DIFFUSE_COLOR
#define RE_PASSNAME_GLOSSY_INDIRECT
#define RE_PASSNAME_AO
#define RE_PASSNAME_DEPRECATED
#define RE_PASSNAME_Z
#define RE_PASSNAME_FREESTYLE
#define RE_PASSNAME_DIFFUSE_DIRECT
#define RE_PASSNAME_INDEXOB
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_unbind()
void GPU_texture_bind(GPUTexture *texture, int unit)
void GPU_texture_unbind(GPUTexture *texture)
eGPUTextureFormat GPU_texture_format(const GPUTexture *texture)
@ PROP_NONE
Definition RNA_types.hh:136
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
#define UI_ITEM_NONE
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter=UI_TEMPLATE_ID_FILTER_ALL, bool live_icon=false, const char *text=nullptr)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
struct GPUShader GPUShader
DOutputSocket output_by_identifier(StringRef identifier) const
void execute_pass(Result &result, GPUTexture *pass_texture, const char *shader_name)
Result * get(Context &context, Image *image, const ImageUser *image_user, const char *pass_name)
virtual rcti get_compositing_region() const =0
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
virtual void set_info_message(StringRef message) const =0
virtual GPUTexture * get_input_texture(const Scene *scene, int view_layer, const char *pass_name)=0
virtual void populate_meta_data_for_pass(const Scene *scene, int view_layer_id, const char *pass_name, MetaData &meta_data) const
NodeOperation(Context &context, DNode node)
bool should_compute_output(StringRef identifier)
Result & get_result(StringRef identifier)
Definition operation.cc:46
ResultPrecision precision() const
Definition result.cc:665
void pass_through(Result &target)
Definition result.cc:289
#define offsetof(t, d)
uint col
void RE_engine_update_render_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer, update_render_passes_cb_t callback, void *callback_data)
RenderEngineType * RE_engines_find(const char *idname)
RenderEngine * RE_engine_create(RenderEngineType *type)
void RE_engine_free(RenderEngine *engine)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
#define G(x, y, z)
void node_type_size_preset(bNodeType *ntype, eNodeSizePreset size)
Definition node.cc:4614
bNodeSocket * node_add_static_socket(bNodeTree *ntree, bNode *node, eNodeSocketInOut in_out, int type, int subtype, const char *identifier, const char *name)
Definition node.cc:2359
void node_type_socket_templates(bNodeType *ntype, bNodeSocketTemplate *inputs, bNodeSocketTemplate *outputs)
Definition node.cc:4570
void node_remove_socket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
Definition node.cc:2405
void node_set_socket_availability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
Definition node.cc:3911
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
static void node_composit_copy_image(bNodeTree *, bNode *dest_node, const bNode *src_node)
static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void node_composit_init_image(bNodeTree *ntree, bNode *node)
static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
static bool node_composit_poll_rlayers(const blender::bke::bNodeType *, const bNodeTree *ntree, const char **r_disabled_hint)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
static void node_composit_copy_rlayers(bNodeTree *, bNode *dest_node, const bNode *src_node)
static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
void extract_alpha(Context &context, Result &input, Result &output)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
VecBase< int32_t, 2 > int2
static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNodePair *available_sockets)
void register_node_type_cmp_image()
static blender::bke::bNodeSocketTemplate cmp_node_rlayers_out[]
void register_node_type_cmp_rlayers()
void node_cmp_rlayers_register_pass(bNodeTree *ntree, bNode *node, Scene *scene, ViewLayer *view_layer, const char *name, eNodeSocketDatatype type)
static void cmp_node_rlayer_create_outputs(bNodeTree *ntree, bNode *node, LinkNodePair *available_sockets)
static void cmp_node_image_add_pass_output(bNodeTree *ntree, bNode *node, const char *name, const char *passname, int rres_index, eNodeSocketDatatype type, int, LinkNodePair *available_sockets, int *prev_index)
void node_cmp_rlayers_outputs(bNodeTree *ntree, bNode *node)
static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rlayer)
#define NUM_LEGACY_SOCKETS
const char * node_cmp_rlayers_sock_to_pass(int sock_index)
static void cmp_node_rlayer_create_outputs_cb(void *userdata, Scene *scene, ViewLayer *view_layer, const char *name, int, const char *, eNodeSocketDatatype type)
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void cmp_node_update_default(bNodeTree *, bNode *node)
bNodeSocket * node_add_socket_from_template(bNodeTree *ntree, bNode *node, bke::bNodeSocketTemplate *stemp, eNodeSocketInOut in_out)
void node_image_label(const bNodeTree *, const bNode *node, char *label, int label_maxncpy)
Definition node_util.cc:193
bool RNA_property_enum_identifier(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_identifier)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition DNA_ID.h:413
void * next
Definition DNA_ID.h:416
struct RenderResult * rr
LinkNode * list
void * first
void * data
Definition RNA_types.hh:42
LinkNodePair * available_sockets
void(* update_render_passes)(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer)
Definition RE_engine.h:115
ListBase passes
Definition RE_pipeline.h:97
ListBase layers
struct FreestyleConfig freestyle_config
struct bNodeSocket * next
char idname[64]
ListBase links
int16_t custom1
struct ID * id
void * storage
ListBase outputs
Compact definition of a node socket.
Definition BKE_node.hh:103
Defines a node type.
Definition BKE_node.hh:218
const char * realtime_compositor_unsupported_message
Definition BKE_node.hh:333
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:324
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:249
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
bool(* poll)(const bNodeType *ntype, const bNodeTree *nodetree, const char **r_disabled_hint)
Definition BKE_node.hh:299
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:257
void(* initfunc_api)(const bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:280
int ymin
int xmin
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126