146 lines
8.3 KiB
C++
146 lines
8.3 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);
|
|
|
|
/* Create one of the concrete subclasses based on the context. Deleting the operation is the
|
|
* caller's responsibility. */
|
|
static PixelOperation *create_operation(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
|