Files
test2/source/blender/compositor/intern/node_operation.cc
Omar Emara e53ac805af Compositor: Avoid redundant output computations
This patch allows the compositor context to specify exactly which
outputs it needs, selecting from: Composite, Viewer, File Output, and
Previews. Previously, the compositor fully executed if any of those were
needed, without granular control on which outputs are needed exactly.

For the viewport compositor engine, it requests Composite and Viewer,
with no Previews or File Outputs.

For the render pipeline, it requests Composite and File Output, with
node Viewer or Previews.

For the interactive compositor, it requests Viewer if the backdrop is
visible or an image editor with the viewer image is visible, it requests
Compositor if an image editor with the render result is visible, it
requests Previews if a node editor has previews overlay enabled. File
outputs are never requested.

Pull Request: https://projects.blender.org/blender/blender/pulls/133960
2025-02-04 08:34:48 +01:00

108 lines
2.9 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_assert.h"
#include "BLI_string_ref.hh"
#include "BLI_timeit.hh"
#include "DNA_node_types.h"
#include "NOD_derived_node_tree.hh"
#include "BKE_node.hh"
#include "COM_algorithm_compute_preview.hh"
#include "COM_context.hh"
#include "COM_input_descriptor.hh"
#include "COM_node_operation.hh"
#include "COM_operation.hh"
#include "COM_result.hh"
#include "COM_scheduler.hh"
#include "COM_utilities.hh"
namespace blender::compositor {
using namespace nodes::derived_node_tree_types;
NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context), node_(node)
{
for (const bNodeSocket *output : node->output_sockets()) {
const ResultType result_type = get_node_socket_result_type(output);
populate_result(output->identifier, context.create_result(result_type));
}
for (const bNodeSocket *input : node->input_sockets()) {
const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input);
declare_input_descriptor(input->identifier, input_descriptor);
}
}
void NodeOperation::evaluate()
{
const timeit::TimePoint before_time = timeit::Clock::now();
Operation::evaluate();
const timeit::TimePoint after_time = timeit::Clock::now();
if (context().profiler()) {
context().profiler()->set_node_evaluation_time(node_.instance_key(), after_time - before_time);
}
}
void NodeOperation::compute_preview()
{
if (bool(context().needed_outputs() & OutputTypes::Previews) && is_node_preview_needed(node())) {
compositor::compute_preview(context(), node(), *get_preview_result());
}
}
Result *NodeOperation::get_preview_result()
{
/* Find the first linked output. */
for (const bNodeSocket *output : node()->output_sockets()) {
Result &output_result = get_result(output->identifier);
if (output_result.should_compute()) {
return &output_result;
}
}
/* No linked outputs, find the first allocated input. */
for (const bNodeSocket *input : node()->input_sockets()) {
Result &input_result = get_input(input->identifier);
if (input_result.is_allocated()) {
return &input_result;
}
}
BLI_assert_unreachable();
return nullptr;
}
void NodeOperation::compute_results_reference_counts(const Schedule &schedule)
{
for (const bNodeSocket *output : this->node()->output_sockets()) {
const DOutputSocket doutput{node().context(), output};
const int reference_count = number_of_inputs_linked_to_output_conditioned(
doutput, [&](DInputSocket input) { return schedule.contains(input.node()); });
get_result(doutput->identifier).set_initial_reference_count(reference_count);
}
}
const DNode &NodeOperation::node() const
{
return node_;
}
const bNode &NodeOperation::bnode() const
{
return *node_;
}
bool NodeOperation::should_compute_output(StringRef identifier)
{
return get_result(identifier).should_compute();
}
} // namespace blender::compositor