Cleanup: Render: Restructure compositor render code

This patch cleanup and refactors the render pipeline compositor render
code to deduplicate code and clarify usage.

The unused this_scene arguemenet was removed, per-node functions were
introduced to simplify loops, C++ Set was used instead of GSet, and
scene change is now detected by any rendered scene in the set.

Pull Request: https://projects.blender.org/blender/blender/pulls/124028
This commit is contained in:
Omar Emara 2024-07-02 17:10:27 +02:00 committed by Omar Emara
parent 9f91ca66bc
commit 29451489ae

@ -34,6 +34,7 @@
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_rect.h"
#include "BLI_set.hh"
#include "BLI_string.h"
#include "BLI_threads.h"
#include "BLI_time.h"
@ -1171,39 +1172,50 @@ static void do_render_compositor_scene(Render *re, Scene *sce, int cfra)
do_render_engine(resc);
}
/**
* Helper call to detect if this scene needs a render,
* or if there's a any render layer to render.
*/
static bool compositor_needs_render(Scene *sce, const bool this_scene)
/* Get the scene referenced by the given node if the node uses its render. Returns nullptr
* otherwise. */
static Scene *get_scene_referenced_by_node(const bNode *node)
{
bNodeTree *ntree = sce->nodetree;
if (node->flag & NODE_MUTED) {
return nullptr;
}
if (node->type == CMP_NODE_R_LAYERS) {
return reinterpret_cast<Scene *>(node->id);
}
else if (node->type == CMP_NODE_CRYPTOMATTE &&
node->custom1 == CMP_NODE_CRYPTOMATTE_SOURCE_RENDER)
{
return reinterpret_cast<Scene *>(node->id);
}
return nullptr;
}
/* Returns true if the given scene needs a render, either because it doesn't use the compositor
* pipeline and thus needs a simple render, or that its compositor node tree requires the scene to
* be rendered. */
static bool compositor_needs_render(Scene *scene)
{
bNodeTree *ntree = scene->nodetree;
if (ntree == nullptr) {
return true;
}
if (sce->use_nodes == false) {
if (scene->use_nodes == false) {
return true;
}
if ((sce->r.scemode & R_DOCOMP) == 0) {
if ((scene->r.scemode & R_DOCOMP) == 0) {
return true;
}
for (const bNode *node : ntree->all_nodes()) {
if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
if (this_scene == 0 || node->id == nullptr || node->id == &sce->id) {
return true;
}
}
if (node->type == CMP_NODE_CRYPTOMATTE &&
node->custom1 == CMP_NODE_CRYPTOMATTE_SOURCE_RENDER && (node->flag & NODE_MUTED) == 0)
{
if (this_scene == 0 || node->id == nullptr || node->id == &sce->id) {
return true;
}
Scene *node_scene = get_scene_referenced_by_node(node);
if (node_scene && node_scene == scene) {
return true;
}
}
return false;
}
@ -1230,62 +1242,43 @@ static bool node_tree_has_composite_output(const bNodeTree *node_tree)
return false;
}
/* Render all scenes within a compositor node tree. */
/* Render all scenes references by the compositor of the given render's scene. */
static void do_render_compositor_scenes(Render *re)
{
int cfra = re->scene->r.cfra;
Scene *restore_scene = re->scene;
if (re->scene->nodetree == nullptr) {
return;
}
bool changed_scene = false;
/* now foreach render-result node we do a full render */
/* results are stored in a way compositor will find it */
GSet *scenes_rendered = BLI_gset_ptr_new(__func__);
/* For each node that requires a scene we do a full render. Results are stored in a way
* compositor will find it. */
blender::Set<Scene *> scenes_rendered;
for (bNode *node : re->scene->nodetree->all_nodes()) {
if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
if (node->id && node->id != (ID *)re->scene) {
Scene *scene = (Scene *)node->id;
if (!BLI_gset_haskey(scenes_rendered, scene) &&
render_scene_has_layers_to_render(scene, nullptr))
{
do_render_compositor_scene(re, scene, cfra);
BLI_gset_add(scenes_rendered, scene);
node->typeinfo->updatefunc(restore_scene->nodetree, node);
if (scene != re->scene) {
changed_scene = true;
}
}
}
Scene *node_scene = get_scene_referenced_by_node(node);
if (!node_scene) {
continue;
}
if (node->type == CMP_NODE_CRYPTOMATTE &&
node->custom1 == CMP_NODE_CRYPTOMATTE_SOURCE_RENDER && (node->flag & NODE_MUTED) == 0)
{
if (node->id && node->id != (ID *)re->scene) {
Scene *scene = (Scene *)node->id;
if (!BLI_gset_haskey(scenes_rendered, scene) &&
render_scene_has_layers_to_render(scene, nullptr))
{
do_render_compositor_scene(re, scene, cfra);
BLI_gset_add(scenes_rendered, scene);
node->typeinfo->updatefunc(restore_scene->nodetree, node);
if (scene != re->scene) {
changed_scene = true;
}
}
}
/* References the current scene, which was already rendered. */
if (node_scene == re->scene) {
continue;
}
/* Scene already rendered as required by another node. */
if (scenes_rendered.contains(node_scene)) {
continue;
}
if (!render_scene_has_layers_to_render(node_scene, nullptr)) {
continue;
}
scenes_rendered.add_new(node_scene);
do_render_compositor_scene(re, node_scene, re->scene->r.cfra);
node->typeinfo->updatefunc(re->scene->nodetree, node);
}
BLI_gset_free(scenes_rendered, nullptr);
if (changed_scene) {
/* If rendered another scene, switch back to the current scene with compositing nodes. */
/* If another scene was rendered, switch back to the current scene. */
if (!scenes_rendered.is_empty()) {
re->current_scene_update(re->scene);
}
}
@ -1308,7 +1301,7 @@ static void do_render_compositor(Render *re)
bNodeTree *ntree = re->pipeline_scene_eval->nodetree;
bool update_newframe = false;
if (compositor_needs_render(re->pipeline_scene_eval, true)) {
if (compositor_needs_render(re->pipeline_scene_eval)) {
/* render the frames
* it could be optimized to render only the needed view
* but what if a scene has a different number of views