In certain setups, nodes whose inputs are single value and whose outputs are expected to be single value wrongly return an image. That's because they wrongly join a pixel operation that operates on images. To fix this, we split pixel operations by their value types. Single value sub-trees get compiled into their own pixel operation and none single value sub-trees get compiled into their own pixel operation. This might unfortunately break up a long chain of pixel operations if one of them was single value. This is solvable, but will require more time and research, so we need to fix the bug first then look into it. Pull Request: https://projects.blender.org/blender/blender/pulls/133701
140 lines
8.0 KiB
C++
140 lines
8.0 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_map.hh"
|
|
#include "BLI_string_ref.hh"
|
|
#include "BLI_vector_set.hh"
|
|
|
|
#include "NOD_derived_node_tree.hh"
|
|
|
|
#include "COM_context.hh"
|
|
#include "COM_operation.hh"
|
|
#include "COM_scheduler.hh"
|
|
|
|
namespace blender::compositor {
|
|
|
|
using namespace nodes::derived_node_tree_types;
|
|
|
|
/* A type representing a contiguous subset of the node execution schedule that will be compiled
|
|
* into a Pixel Operation. */
|
|
using PixelCompileUnit = VectorSet<DNode>;
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Pixel Operation
|
|
*
|
|
* An operation that is evaluated pixel-wise and is compiled from a contiguous subset of the node
|
|
* execution schedule, whose nodes all represent pixel-wise operations. The subset of the node
|
|
* execution schedule is called a Pixel Compile Unit and contains nodes that are called Pixel
|
|
* nodes, see the discussion in COM_compile_state.hh for more information. Since the nodes inside
|
|
* the compile unit are all pixel wise, they can be combined into a single operation that can be
|
|
* evaluated more efficiently. This is an abstract class that should be implemented to compile and
|
|
* evaluate the compile unit as needed.
|
|
*
|
|
* Consider the following node graph with a node execution schedule denoted by the number on each
|
|
* node. The compiler may decide to compile a subset of the execution schedule into a pixel
|
|
* operation if they are all pixel nodes, in this case, the nodes from 3 to 5 were compiled
|
|
* together into a pixel operation. This subset is called the pixel compile unit. See the
|
|
* discussion in COM_evaluator.hh for more information on the compilation process. Links that are
|
|
* internal to the pixel operation are established between the input and outputs of the pixel
|
|
* nodes, for instance, the links between nodes 3 and 4 as well as those between nodes 4 and 5.
|
|
* However, links that cross the boundary of the pixel operation needs special handling.
|
|
*
|
|
* Pixel Operation
|
|
* +------------------------------------------------------+
|
|
* .------------. | .------------. .------------. .------------. | .------------.
|
|
* | Node 1 | | | Node 3 | | Node 4 | | Node 5 | | | Node 6 |
|
|
* | |----|--| |--| |------| |--|--| |
|
|
* | | .-|--| | | | .---| | | | |
|
|
* '------------' | | '------------' '------------' | '------------' | '------------'
|
|
* | +----------------------------------|-------------------+
|
|
* .------------. | |
|
|
* | Node 2 | | |
|
|
* | |--'------------------------------------'
|
|
* | |
|
|
* '------------'
|
|
*
|
|
* Links from nodes that are not part of the pixel operation to nodes that are part of the pixel
|
|
* operation are considered inputs of the operation itself and are declared as such. For instance,
|
|
* the link from node 1 to node 3 is declared as an input to the operation, and the same applies
|
|
* for the links from node 2 to nodes 3 and 5. Note, however, that only one input is declared for
|
|
* each distinct output socket, so both links from node 2 share the same input of the operation.
|
|
*
|
|
* Links from nodes that are part of the pixel operation to nodes that are not part of the pixel
|
|
* operation are considered outputs of the operation itself and are declared as such. For instance,
|
|
* the link from node 5 to node 6 is declared as an output to the operation. */
|
|
class PixelOperation : public Operation {
|
|
protected:
|
|
/* The compile unit that will be compiled into this pixel operation. */
|
|
PixelCompileUnit compile_unit_;
|
|
/* A reference to the node execution schedule that is being compiled. */
|
|
const Schedule &schedule_;
|
|
/* A map that associates the identifier of each input of the operation with the output socket it
|
|
* is linked to. This is needed to help the compiler establish links between operations. */
|
|
Map<std::string, DOutputSocket> inputs_to_linked_outputs_map_;
|
|
/* A map that associates the output socket of a node that is not part of the pixel operation to
|
|
* the identifier of the input of the operation that was declared for it. */
|
|
Map<DOutputSocket, std::string> outputs_to_declared_inputs_map_;
|
|
/* A map that associates the identifier of each input of the operation with the number of node
|
|
* inputs that use it, that is, its reference count. This is needed to properly release inputs
|
|
* after evaluation, since the results that provide the inputs aren't aware that multiple of
|
|
* their outgoing links are now part of a single pixel operation, so we need to release the
|
|
* inputs with their internal reference count stored here. See PixelOperation::release_inputs. */
|
|
Map<std::string, int> inputs_to_reference_counts_map_;
|
|
/* A map that associates the output socket that provides the result of an output of the operation
|
|
* with the identifier of that output. This is needed to help the compiler establish links
|
|
* between operations. */
|
|
Map<DOutputSocket, std::string> output_sockets_to_output_identifiers_map_;
|
|
/* A vector set that stores all output sockets that are used as previews for nodes inside the
|
|
* pixel operation. */
|
|
VectorSet<DOutputSocket> preview_outputs_;
|
|
|
|
public:
|
|
PixelOperation(Context &context, PixelCompileUnit &compile_unit, const Schedule &schedule);
|
|
|
|
/* Returns the maximum number of outputs that the PixelOperation can have. Pixel compile units
|
|
* need to be split into smaller units if the numbers of outputs they have is more than the
|
|
* number returned by this method. */
|
|
static int maximum_number_of_outputs(Context &context);
|
|
|
|
/* Compute a node preview for all nodes in the pixel operations if the node requires a preview.
|
|
*
|
|
* Previews are computed from results that are populated for outputs that are used to compute
|
|
* previews even if they are internally linked, and those outputs are stored and tracked in the
|
|
* preview_outputs_ vector set, see the populate_results_for_node method for more information. */
|
|
void compute_preview() override;
|
|
|
|
/* Get the identifier of the operation output corresponding to the given output socket. This is
|
|
* called by the compiler to identify the operation output that provides the result for an input
|
|
* by providing the output socket that the input is linked to. See
|
|
* output_sockets_to_output_identifiers_map_ for more information. */
|
|
StringRef get_output_identifier_from_output_socket(DOutputSocket output_socket);
|
|
|
|
/* Get a reference to the inputs to linked outputs map of the operation. This is called by the
|
|
* compiler to identify the output that each input of the operation is linked to for correct
|
|
* input mapping. See inputs_to_linked_outputs_map_ for more information. */
|
|
Map<std::string, DOutputSocket> &get_inputs_to_linked_outputs_map();
|
|
|
|
/* Compute and set the initial reference counts of all the results of the operation. The
|
|
* reference counts of the results are the number of operations that use those results, which is
|
|
* computed as the number of inputs linked to the output corresponding to each of the results of
|
|
* the operation, but only the linked inputs whose node is part of the schedule but not part of
|
|
* the pixel operation, since inputs that are part of the pixel operations are internal links.
|
|
*
|
|
* Additionally, results that are used as node previews gets an extra reference count because
|
|
* they are referenced and released by the compute_preview method.
|
|
*
|
|
* The node execution schedule is given as an input. */
|
|
void compute_results_reference_counts(const Schedule &schedule);
|
|
|
|
protected:
|
|
/* Release the results that are mapped to the inputs of the operation, making sure to release the
|
|
* input with a count equivalent to its reference count stored in inputs_to_reference_counts_map_
|
|
* to avoid leaking the result. */
|
|
void release_inputs() override;
|
|
};
|
|
|
|
} // namespace blender::compositor
|