2014-04-15 16:06:12 +02:00
|
|
|
/*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2019-02-18 07:21:50 +11:00
|
|
|
*
|
|
|
|
|
* Copyright 2013, Blender Foundation.
|
2014-04-15 16:06:12 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
|
|
|
|
|
#include "COM_Converter.h"
|
|
|
|
|
#include "COM_Debug.h"
|
|
|
|
|
#include "COM_ExecutionSystem.h"
|
|
|
|
|
#include "COM_Node.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "COM_NodeConverter.h"
|
2014-04-15 16:06:12 +02:00
|
|
|
#include "COM_SocketProxyNode.h"
|
|
|
|
|
|
|
|
|
|
#include "COM_NodeOperation.h"
|
|
|
|
|
#include "COM_PreviewOperation.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "COM_ReadBufferOperation.h"
|
|
|
|
|
#include "COM_SetColorOperation.h"
|
2014-04-15 16:06:12 +02:00
|
|
|
#include "COM_SetValueOperation.h"
|
|
|
|
|
#include "COM_SetVectorOperation.h"
|
|
|
|
|
#include "COM_SocketProxyOperation.h"
|
2014-07-08 12:48:41 +02:00
|
|
|
#include "COM_ViewerOperation.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "COM_WriteBufferOperation.h"
|
2014-04-15 16:06:12 +02:00
|
|
|
|
|
|
|
|
#include "COM_NodeOperationBuilder.h" /* own include */
|
|
|
|
|
|
|
|
|
|
NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree)
|
2020-11-06 17:49:09 +01:00
|
|
|
: m_context(context), m_current_node(nullptr), m_active_viewer(nullptr)
|
2014-04-15 16:06:12 +02:00
|
|
|
{
|
|
|
|
|
m_graph.from_bNodeTree(*context, b_nodetree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeOperationBuilder::~NodeOperationBuilder()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
|
|
|
|
|
{
|
|
|
|
|
/* interface handle for nodes */
|
|
|
|
|
NodeConverter converter(this);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
for (int index = 0; index < m_graph.nodes().size(); index++) {
|
|
|
|
|
Node *node = (Node *)m_graph.nodes()[index];
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
m_current_node = node;
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
DebugInfo::node_to_operations(node);
|
|
|
|
|
node->convertToOperations(converter, *m_context);
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2020-11-06 17:49:09 +01:00
|
|
|
m_current_node = nullptr;
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* The input map constructed by nodes maps operation inputs to node inputs.
|
|
|
|
|
* Inverting yields a map of node inputs to all connected operation inputs,
|
|
|
|
|
* so multiple operations can use the same node input.
|
|
|
|
|
*/
|
|
|
|
|
OpInputInverseMap inverse_input_map;
|
2019-09-08 03:31:49 +10:00
|
|
|
for (InputSocketMap::const_iterator it = m_input_map.begin(); it != m_input_map.end(); ++it) {
|
2021-03-16 14:15:36 +01:00
|
|
|
inverse_input_map[it->second].append(it->first);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2021-03-05 16:28:08 +01:00
|
|
|
for (const NodeGraph::Link &link : m_graph.links()) {
|
|
|
|
|
NodeOutput *from = link.from;
|
|
|
|
|
NodeInput *to = link.to;
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationOutput *op_from = find_operation_output(m_output_map, from);
|
2021-03-16 14:15:36 +01:00
|
|
|
const blender::Vector<NodeOperationInput *> &op_to_list = find_operation_inputs(
|
|
|
|
|
inverse_input_map, to);
|
|
|
|
|
if (!op_from || op_to_list.is_empty()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
/* XXX allow this? error/debug message? */
|
2019-05-01 10:50:02 +10:00
|
|
|
// BLI_assert(false);
|
2014-04-25 12:00:35 +02:00
|
|
|
/* XXX note: this can happen with certain nodes (e.g. OutputFile)
|
|
|
|
|
* which only generate operations in certain circumstances (rendering)
|
|
|
|
|
* just let this pass silently for now ...
|
|
|
|
|
*/
|
2014-04-15 16:06:12 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2021-03-16 14:15:36 +01:00
|
|
|
for (NodeOperationInput *op_to : op_to_list) {
|
2014-04-15 16:06:12 +02:00
|
|
|
addLink(op_from, op_to);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2015-03-27 17:25:12 +05:00
|
|
|
add_operation_input_constants();
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2019-05-24 14:08:21 +02:00
|
|
|
resolve_proxies();
|
|
|
|
|
|
2020-06-19 14:49:36 +02:00
|
|
|
add_datatype_conversions();
|
|
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
determineResolutions();
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* surround complex ops with read/write buffer */
|
|
|
|
|
add_complex_operation_buffers();
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* links not available from here on */
|
|
|
|
|
/* XXX make m_links a local variable to avoid confusion! */
|
|
|
|
|
m_links.clear();
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
prune_operations();
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* ensure topological (link-based) order of nodes */
|
|
|
|
|
/*sort_operations();*/ /* not needed yet */
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* create execution groups */
|
|
|
|
|
group_operations();
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* transfer resulting operations to the system */
|
|
|
|
|
system->set_operations(m_operations, m_groups);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::addOperation(NodeOperation *operation)
|
|
|
|
|
{
|
2021-03-05 16:45:11 +01:00
|
|
|
m_operations.append(operation);
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket,
|
|
|
|
|
NodeOperationInput *operation_socket)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(m_current_node);
|
|
|
|
|
BLI_assert(node_socket->getNode() == m_current_node);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* note: this maps operation sockets to node sockets.
|
|
|
|
|
* for resolving links the map will be inverted first in convertToOperations,
|
|
|
|
|
* to get a list of links for each node input socket.
|
|
|
|
|
*/
|
|
|
|
|
m_input_map[operation_socket] = node_socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::mapOutputSocket(NodeOutput *node_socket,
|
|
|
|
|
NodeOperationOutput *operation_socket)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(m_current_node);
|
|
|
|
|
BLI_assert(node_socket->getNode() == m_current_node);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
m_output_map[node_socket] = operation_socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::addLink(NodeOperationOutput *from, NodeOperationInput *to)
|
|
|
|
|
{
|
2019-04-23 11:21:22 +10:00
|
|
|
if (to->isConnected()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
return;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2021-03-16 14:15:36 +01:00
|
|
|
m_links.append(Link(from, to));
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* register with the input */
|
|
|
|
|
to->setLink(from);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::removeInputLink(NodeOperationInput *to)
|
|
|
|
|
{
|
2021-03-16 14:15:36 +01:00
|
|
|
int index = 0;
|
|
|
|
|
for (Link &link : m_links) {
|
2014-04-15 16:06:12 +02:00
|
|
|
if (link.to() == to) {
|
|
|
|
|
/* unregister with the input */
|
2020-11-06 17:49:09 +01:00
|
|
|
to->setLink(nullptr);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2021-03-16 14:15:36 +01:00
|
|
|
m_links.remove(index);
|
2014-04-15 16:06:12 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2021-03-16 14:15:36 +01:00
|
|
|
index++;
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeInput *NodeOperationBuilder::find_node_input(const InputSocketMap &map,
|
|
|
|
|
NodeOperationInput *op_input)
|
|
|
|
|
{
|
|
|
|
|
InputSocketMap::const_iterator it = map.find(op_input);
|
|
|
|
|
return (it != map.end() ? it->second : NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 14:15:36 +01:00
|
|
|
const blender::Vector<NodeOperationInput *> &NodeOperationBuilder::find_operation_inputs(
|
2014-04-15 16:06:12 +02:00
|
|
|
const OpInputInverseMap &map, NodeInput *node_input)
|
|
|
|
|
{
|
2021-03-16 14:15:36 +01:00
|
|
|
static const blender::Vector<NodeOperationInput *> empty_list;
|
2014-04-15 16:06:12 +02:00
|
|
|
OpInputInverseMap::const_iterator it = map.find(node_input);
|
|
|
|
|
return (it != map.end() ? it->second : empty_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeOperationOutput *NodeOperationBuilder::find_operation_output(const OutputSocketMap &map,
|
|
|
|
|
NodeOutput *node_output)
|
|
|
|
|
{
|
|
|
|
|
OutputSocketMap::const_iterator it = map.find(node_output);
|
|
|
|
|
return (it != map.end() ? it->second : NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PreviewOperation *NodeOperationBuilder::make_preview_operation() const
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(m_current_node);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2019-04-23 11:21:22 +10:00
|
|
|
if (!(m_current_node->getbNode()->flag & NODE_PREVIEW)) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
/* previews only in the active group */
|
2019-04-23 11:21:22 +10:00
|
|
|
if (!m_current_node->isInActiveGroup()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
/* do not calculate previews of hidden nodes */
|
2019-04-23 11:21:22 +10:00
|
|
|
if (m_current_node->getbNode()->flag & NODE_HIDDEN) {
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
bNodeInstanceHash *previews = m_context->getPreviewHash();
|
|
|
|
|
if (previews) {
|
|
|
|
|
PreviewOperation *operation = new PreviewOperation(m_context->getViewSettings(),
|
|
|
|
|
m_context->getDisplaySettings());
|
|
|
|
|
operation->setbNodeTree(m_context->getbNodeTree());
|
|
|
|
|
operation->verifyPreview(previews, m_current_node->getInstanceKey());
|
|
|
|
|
return operation;
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::addPreview(NodeOperationOutput *output)
|
|
|
|
|
{
|
|
|
|
|
PreviewOperation *operation = make_preview_operation();
|
|
|
|
|
if (operation) {
|
|
|
|
|
addOperation(operation);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
addLink(output, operation->getInputSocket(0));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::addNodeInputPreview(NodeInput *input)
|
|
|
|
|
{
|
|
|
|
|
PreviewOperation *operation = make_preview_operation();
|
|
|
|
|
if (operation) {
|
|
|
|
|
addOperation(operation);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
mapInputSocket(input, operation->getInputSocket(0));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-08 12:48:41 +02:00
|
|
|
void NodeOperationBuilder::registerViewer(ViewerOperation *viewer)
|
|
|
|
|
{
|
|
|
|
|
if (m_active_viewer) {
|
|
|
|
|
if (m_current_node->isInActiveGroup()) {
|
|
|
|
|
/* deactivate previous viewer */
|
|
|
|
|
m_active_viewer->setActive(false);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-07-08 12:48:41 +02:00
|
|
|
m_active_viewer = viewer;
|
|
|
|
|
viewer->setActive(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (m_current_node->getbNodeTree() == m_context->getbNodeTree()) {
|
|
|
|
|
m_active_viewer = viewer;
|
|
|
|
|
viewer->setActive(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/****************************
|
|
|
|
|
**** Optimization Steps ****
|
|
|
|
|
****************************/
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::add_datatype_conversions()
|
|
|
|
|
{
|
2021-03-16 14:15:36 +01:00
|
|
|
blender::Vector<Link> convert_links;
|
2021-03-16 13:47:30 +01:00
|
|
|
for (const Link &link : m_links) {
|
2014-07-15 10:55:49 +02:00
|
|
|
/* proxy operations can skip data type conversion */
|
|
|
|
|
NodeOperation *from_op = &link.from()->getOperation();
|
|
|
|
|
NodeOperation *to_op = &link.to()->getOperation();
|
2019-04-23 11:21:22 +10:00
|
|
|
if (!(from_op->useDatatypeConversion() || to_op->useDatatypeConversion())) {
|
2014-07-15 10:55:49 +02:00
|
|
|
continue;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2019-04-23 11:21:22 +10:00
|
|
|
if (link.from()->getDataType() != link.to()->getDataType()) {
|
2021-03-16 14:15:36 +01:00
|
|
|
convert_links.append(link);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
2021-03-16 13:47:30 +01:00
|
|
|
for (const Link &link : convert_links) {
|
2021-03-05 10:54:29 +01:00
|
|
|
NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to());
|
2014-04-15 16:06:12 +02:00
|
|
|
if (converter) {
|
|
|
|
|
addOperation(converter);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
removeInputLink(link.to());
|
|
|
|
|
addLink(link.from(), converter->getInputSocket(0));
|
|
|
|
|
addLink(converter->getOutputSocket(0), link.to());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::add_operation_input_constants()
|
|
|
|
|
{
|
|
|
|
|
/* Note: unconnected inputs cached first to avoid modifying
|
|
|
|
|
* m_operations while iterating over it
|
|
|
|
|
*/
|
2020-12-09 16:29:11 +01:00
|
|
|
using Inputs = std::vector<NodeOperationInput *>;
|
2014-04-15 16:06:12 +02:00
|
|
|
Inputs pending_inputs;
|
2021-03-05 16:45:11 +01:00
|
|
|
for (NodeOperation *op : m_operations) {
|
2019-09-08 03:31:49 +10:00
|
|
|
for (int k = 0; k < op->getNumberOfInputSockets(); ++k) {
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationInput *input = op->getInputSocket(k);
|
2019-04-23 11:21:22 +10:00
|
|
|
if (!input->isConnected()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
pending_inputs.push_back(input);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-08 03:31:49 +10:00
|
|
|
for (Inputs::const_iterator it = pending_inputs.begin(); it != pending_inputs.end(); ++it) {
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationInput *input = *it;
|
|
|
|
|
add_input_constant_value(input, find_node_input(m_input_map, input));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
void NodeOperationBuilder::add_input_constant_value(NodeOperationInput *input,
|
|
|
|
|
NodeInput *node_input)
|
|
|
|
|
{
|
|
|
|
|
switch (input->getDataType()) {
|
|
|
|
|
case COM_DT_VALUE: {
|
|
|
|
|
float value;
|
2019-04-23 11:21:22 +10:00
|
|
|
if (node_input && node_input->getbNodeSocket()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
value = node_input->getEditorValueFloat();
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2014-04-15 16:06:12 +02:00
|
|
|
value = 0.0f;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
SetValueOperation *op = new SetValueOperation();
|
|
|
|
|
op->setValue(value);
|
|
|
|
|
addOperation(op);
|
|
|
|
|
addLink(op->getOutputSocket(), input);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case COM_DT_COLOR: {
|
|
|
|
|
float value[4];
|
2019-04-23 11:21:22 +10:00
|
|
|
if (node_input && node_input->getbNodeSocket()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
node_input->getEditorValueColor(value);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2014-04-15 16:06:12 +02:00
|
|
|
zero_v4(value);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
SetColorOperation *op = new SetColorOperation();
|
|
|
|
|
op->setChannels(value);
|
|
|
|
|
addOperation(op);
|
|
|
|
|
addLink(op->getOutputSocket(), input);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case COM_DT_VECTOR: {
|
|
|
|
|
float value[3];
|
2019-04-23 11:21:22 +10:00
|
|
|
if (node_input && node_input->getbNodeSocket()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
node_input->getEditorValueVector(value);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2014-04-15 16:06:12 +02:00
|
|
|
zero_v3(value);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
SetVectorOperation *op = new SetVectorOperation();
|
|
|
|
|
op->setVector(value);
|
|
|
|
|
addOperation(op);
|
|
|
|
|
addLink(op->getOutputSocket(), input);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::resolve_proxies()
|
|
|
|
|
{
|
2021-03-16 14:15:36 +01:00
|
|
|
blender::Vector<Link> proxy_links;
|
|
|
|
|
for (const Link &link : m_links) {
|
2014-04-15 16:06:12 +02:00
|
|
|
/* don't replace links from proxy to proxy, since we may need them for replacing others! */
|
|
|
|
|
if (link.from()->getOperation().isProxyOperation() &&
|
2014-04-17 20:00:49 +10:00
|
|
|
!link.to()->getOperation().isProxyOperation()) {
|
2021-03-16 14:15:36 +01:00
|
|
|
proxy_links.append(link);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-03-16 14:15:36 +01:00
|
|
|
for (const Link &link : proxy_links) {
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationInput *to = link.to();
|
|
|
|
|
NodeOperationOutput *from = link.from();
|
|
|
|
|
do {
|
|
|
|
|
/* walk upstream bypassing the proxy operation */
|
|
|
|
|
from = from->getOperation().getInputSocket(0)->getLink();
|
|
|
|
|
} while (from && from->getOperation().isProxyOperation());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
removeInputLink(to);
|
|
|
|
|
/* we may not have a final proxy input link,
|
|
|
|
|
* in that case it just gets dropped
|
|
|
|
|
*/
|
2019-04-23 11:21:22 +10:00
|
|
|
if (from) {
|
2014-04-15 16:06:12 +02:00
|
|
|
addLink(from, to);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::determineResolutions()
|
|
|
|
|
{
|
|
|
|
|
/* determine all resolutions of the operations (Width/Height) */
|
2021-03-05 16:45:11 +01:00
|
|
|
for (NodeOperation *op : m_operations) {
|
2014-04-15 16:06:12 +02:00
|
|
|
if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) {
|
|
|
|
|
unsigned int resolution[2] = {0, 0};
|
|
|
|
|
unsigned int preferredResolution[2] = {0, 0};
|
|
|
|
|
op->determineResolution(resolution, preferredResolution);
|
|
|
|
|
op->setResolution(resolution);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-03-05 16:45:11 +01:00
|
|
|
for (NodeOperation *op : m_operations) {
|
2014-04-15 16:06:12 +02:00
|
|
|
if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) {
|
|
|
|
|
unsigned int resolution[2] = {0, 0};
|
|
|
|
|
unsigned int preferredResolution[2] = {0, 0};
|
|
|
|
|
op->determineResolution(resolution, preferredResolution);
|
|
|
|
|
op->setResolution(resolution);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* add convert resolution operations when needed */
|
|
|
|
|
{
|
2021-03-16 14:15:36 +01:00
|
|
|
blender::Vector<Link> convert_links;
|
|
|
|
|
for (const Link &link : m_links) {
|
2014-04-15 16:06:12 +02:00
|
|
|
if (link.to()->getResizeMode() != COM_SC_NO_RESIZE) {
|
|
|
|
|
NodeOperation &from_op = link.from()->getOperation();
|
|
|
|
|
NodeOperation &to_op = link.to()->getOperation();
|
2019-04-23 11:21:22 +10:00
|
|
|
if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) {
|
2021-03-16 14:15:36 +01:00
|
|
|
convert_links.append(link);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
2021-03-16 14:15:36 +01:00
|
|
|
for (const Link &link : convert_links) {
|
2021-03-05 10:41:45 +01:00
|
|
|
COM_convert_resolution(*this, link.from(), link.to());
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-03-16 14:15:36 +01:00
|
|
|
blender::Vector<NodeOperationInput *> NodeOperationBuilder::cache_output_links(
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationOutput *output) const
|
|
|
|
|
{
|
2021-03-16 14:15:36 +01:00
|
|
|
blender::Vector<NodeOperationInput *> inputs;
|
|
|
|
|
for (const Link &link : m_links) {
|
2019-04-23 11:21:22 +10:00
|
|
|
if (link.from() == output) {
|
2021-03-16 14:15:36 +01:00
|
|
|
inputs.append(link.to());
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
return inputs;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation(
|
|
|
|
|
NodeOperationOutput *output) const
|
|
|
|
|
{
|
2021-03-16 14:15:36 +01:00
|
|
|
for (const Link &link : m_links) {
|
2014-04-15 16:06:12 +02:00
|
|
|
if (link.from() == output) {
|
|
|
|
|
NodeOperation &op = link.to()->getOperation();
|
2019-04-23 11:21:22 +10:00
|
|
|
if (op.isWriteBufferOperation()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
return (WriteBufferOperation *)(&op);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-27 15:49:07 +05:00
|
|
|
void NodeOperationBuilder::add_input_buffers(NodeOperation * /*operation*/,
|
|
|
|
|
NodeOperationInput *input)
|
2014-04-15 16:06:12 +02:00
|
|
|
{
|
2019-04-23 11:21:22 +10:00
|
|
|
if (!input->isConnected()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
return;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationOutput *output = input->getLink();
|
|
|
|
|
if (output->getOperation().isReadBufferOperation()) {
|
|
|
|
|
/* input is already buffered, no need to add another */
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* this link will be replaced below */
|
|
|
|
|
removeInputLink(input);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* check of other end already has write operation, otherwise add a new one */
|
|
|
|
|
WriteBufferOperation *writeoperation = find_attached_write_buffer_operation(output);
|
|
|
|
|
if (!writeoperation) {
|
2015-01-19 18:13:26 +01:00
|
|
|
writeoperation = new WriteBufferOperation(output->getDataType());
|
2014-04-15 16:06:12 +02:00
|
|
|
writeoperation->setbNodeTree(m_context->getbNodeTree());
|
|
|
|
|
addOperation(writeoperation);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
addLink(output, writeoperation->getInputSocket(0));
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
writeoperation->readResolutionFromInputSocket();
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* add readbuffer op for the input */
|
2015-01-19 18:13:26 +01:00
|
|
|
ReadBufferOperation *readoperation = new ReadBufferOperation(output->getDataType());
|
2014-04-15 16:06:12 +02:00
|
|
|
readoperation->setMemoryProxy(writeoperation->getMemoryProxy());
|
|
|
|
|
this->addOperation(readoperation);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
addLink(readoperation->getOutputSocket(), input);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
readoperation->readResolutionFromWriteBuffer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::add_output_buffers(NodeOperation *operation,
|
|
|
|
|
NodeOperationOutput *output)
|
|
|
|
|
{
|
|
|
|
|
/* cache connected sockets, so we can safely remove links first before replacing them */
|
2021-03-16 14:15:36 +01:00
|
|
|
blender::Vector<NodeOperationInput *> targets = cache_output_links(output);
|
|
|
|
|
if (targets.is_empty()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
return;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2020-11-06 17:49:09 +01:00
|
|
|
WriteBufferOperation *writeOperation = nullptr;
|
2021-03-16 14:15:36 +01:00
|
|
|
for (NodeOperationInput *target : targets) {
|
2014-04-15 16:06:12 +02:00
|
|
|
/* try to find existing write buffer operation */
|
|
|
|
|
if (target->getOperation().isWriteBufferOperation()) {
|
2020-11-06 17:49:09 +01:00
|
|
|
BLI_assert(writeOperation == nullptr); /* there should only be one write op connected */
|
2014-04-15 16:06:12 +02:00
|
|
|
writeOperation = (WriteBufferOperation *)(&target->getOperation());
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* remove all links to other nodes */
|
|
|
|
|
removeInputLink(target);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* if no write buffer operation exists yet, create a new one */
|
|
|
|
|
if (!writeOperation) {
|
2015-01-19 18:13:26 +01:00
|
|
|
writeOperation = new WriteBufferOperation(operation->getOutputSocket()->getDataType());
|
2014-04-15 16:06:12 +02:00
|
|
|
writeOperation->setbNodeTree(m_context->getbNodeTree());
|
|
|
|
|
addOperation(writeOperation);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
addLink(output, writeOperation->getInputSocket(0));
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
writeOperation->readResolutionFromInputSocket();
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* add readbuffer op for every former connected input */
|
2021-03-16 14:15:36 +01:00
|
|
|
for (NodeOperationInput *target : targets) {
|
2019-04-23 11:21:22 +10:00
|
|
|
if (&target->getOperation() == writeOperation) {
|
2014-04-15 16:06:12 +02:00
|
|
|
continue; /* skip existing write op links */
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2015-01-19 18:13:26 +01:00
|
|
|
ReadBufferOperation *readoperation = new ReadBufferOperation(
|
|
|
|
|
operation->getOutputSocket()->getDataType());
|
2014-04-15 16:06:12 +02:00
|
|
|
readoperation->setMemoryProxy(writeOperation->getMemoryProxy());
|
|
|
|
|
addOperation(readoperation);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
addLink(readoperation->getOutputSocket(), target);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
readoperation->readResolutionFromWriteBuffer();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::add_complex_operation_buffers()
|
|
|
|
|
{
|
|
|
|
|
/* note: complex ops and get cached here first, since adding operations
|
|
|
|
|
* will invalidate iterators over the main m_operations
|
|
|
|
|
*/
|
2021-03-05 16:45:11 +01:00
|
|
|
blender::Vector<NodeOperation *> complex_ops;
|
|
|
|
|
for (NodeOperation *operation : m_operations) {
|
|
|
|
|
if (operation->isComplex()) {
|
|
|
|
|
complex_ops.append(operation);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
|
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2021-03-05 16:45:11 +01:00
|
|
|
for (NodeOperation *op : complex_ops) {
|
2014-04-15 16:06:12 +02:00
|
|
|
DebugInfo::operation_read_write_buffer(op);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2019-04-23 11:21:22 +10:00
|
|
|
for (int index = 0; index < op->getNumberOfInputSockets(); index++) {
|
2014-04-15 16:06:12 +02:00
|
|
|
add_input_buffers(op, op->getInputSocket(index));
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2019-04-23 11:21:22 +10:00
|
|
|
for (int index = 0; index < op->getNumberOfOutputSockets(); index++) {
|
2014-04-15 16:06:12 +02:00
|
|
|
add_output_buffers(op, op->getOutputSocket(index));
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 12:46:43 +01:00
|
|
|
using Tags = std::set<NodeOperation *>;
|
2014-04-15 16:06:12 +02:00
|
|
|
|
|
|
|
|
static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *op)
|
|
|
|
|
{
|
2019-04-23 11:21:22 +10:00
|
|
|
if (reachable.find(op) != reachable.end()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
return;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
reachable.insert(op);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2019-09-08 00:12:26 +10:00
|
|
|
for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationInput *input = op->getInputSocket(i);
|
2019-04-23 11:21:22 +10:00
|
|
|
if (input->isConnected()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
find_reachable_operations_recursive(reachable, &input->getLink()->getOperation());
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* associated write-buffer operations are executed as well */
|
|
|
|
|
if (op->isReadBufferOperation()) {
|
|
|
|
|
ReadBufferOperation *read_op = (ReadBufferOperation *)op;
|
|
|
|
|
MemoryProxy *memproxy = read_op->getMemoryProxy();
|
|
|
|
|
find_reachable_operations_recursive(reachable, memproxy->getWriteBufferOperation());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::prune_operations()
|
|
|
|
|
{
|
|
|
|
|
Tags reachable;
|
2021-03-05 16:45:11 +01:00
|
|
|
for (NodeOperation *op : m_operations) {
|
2014-04-15 16:06:12 +02:00
|
|
|
/* output operations are primary executed operations */
|
2019-04-23 11:21:22 +10:00
|
|
|
if (op->isOutputOperation(m_context->isRendering())) {
|
2014-04-15 16:06:12 +02:00
|
|
|
find_reachable_operations_recursive(reachable, op);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* delete unreachable operations */
|
2021-03-05 16:45:11 +01:00
|
|
|
blender::Vector<NodeOperation *> reachable_ops;
|
|
|
|
|
for (NodeOperation *op : m_operations) {
|
2019-04-23 11:21:22 +10:00
|
|
|
if (reachable.find(op) != reachable.end()) {
|
2021-03-05 16:45:11 +01:00
|
|
|
reachable_ops.append(op);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2014-04-15 16:06:12 +02:00
|
|
|
delete op;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
/* finally replace the operations list with the pruned list */
|
|
|
|
|
m_operations = reachable_ops;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* topological (depth-first) sorting of operations */
|
2021-03-05 16:45:11 +01:00
|
|
|
static void sort_operations_recursive(blender::Vector<NodeOperation *> &sorted,
|
2014-04-15 16:06:12 +02:00
|
|
|
Tags &visited,
|
|
|
|
|
NodeOperation *op)
|
|
|
|
|
{
|
2019-04-23 11:21:22 +10:00
|
|
|
if (visited.find(op) != visited.end()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
return;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
visited.insert(op);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2019-09-08 00:12:26 +10:00
|
|
|
for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationInput *input = op->getInputSocket(i);
|
2019-04-23 11:21:22 +10:00
|
|
|
if (input->isConnected()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
sort_operations_recursive(sorted, visited, &input->getLink()->getOperation());
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2021-03-05 16:45:11 +01:00
|
|
|
sorted.append(op);
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::sort_operations()
|
|
|
|
|
{
|
2021-03-05 16:45:11 +01:00
|
|
|
blender::Vector<NodeOperation *> sorted;
|
2014-04-15 16:06:12 +02:00
|
|
|
sorted.reserve(m_operations.size());
|
|
|
|
|
Tags visited;
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2021-03-05 16:45:11 +01:00
|
|
|
for (NodeOperation *operation : m_operations) {
|
|
|
|
|
sort_operations_recursive(sorted, visited, operation);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
m_operations = sorted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void add_group_operations_recursive(Tags &visited, NodeOperation *op, ExecutionGroup *group)
|
|
|
|
|
{
|
2019-04-23 11:21:22 +10:00
|
|
|
if (visited.find(op) != visited.end()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
return;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
visited.insert(op);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2019-04-23 11:21:22 +10:00
|
|
|
if (!group->addOperation(op)) {
|
2014-04-15 16:06:12 +02:00
|
|
|
return;
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* add all eligible input ops to the group */
|
2019-09-08 00:12:26 +10:00
|
|
|
for (int i = 0; i < op->getNumberOfInputSockets(); i++) {
|
2014-04-15 16:06:12 +02:00
|
|
|
NodeOperationInput *input = op->getInputSocket(i);
|
2019-04-23 11:21:22 +10:00
|
|
|
if (input->isConnected()) {
|
2014-04-15 16:06:12 +02:00
|
|
|
add_group_operations_recursive(visited, &input->getLink()->getOperation(), group);
|
2019-04-23 11:21:22 +10:00
|
|
|
}
|
2014-04-15 16:06:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op)
|
|
|
|
|
{
|
|
|
|
|
ExecutionGroup *group = new ExecutionGroup();
|
2021-03-05 16:21:56 +01:00
|
|
|
m_groups.append(group);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
Tags visited;
|
|
|
|
|
add_group_operations_recursive(visited, op, group);
|
2018-06-17 17:05:29 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
return group;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeOperationBuilder::group_operations()
|
|
|
|
|
{
|
2021-03-05 16:45:11 +01:00
|
|
|
for (NodeOperation *op : m_operations) {
|
2014-04-15 16:06:12 +02:00
|
|
|
if (op->isOutputOperation(m_context->isRendering())) {
|
|
|
|
|
ExecutionGroup *group = make_group(op);
|
|
|
|
|
group->setOutputExecutionGroup(true);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-15 16:06:12 +02:00
|
|
|
/* add new groups for associated memory proxies where needed */
|
|
|
|
|
if (op->isReadBufferOperation()) {
|
|
|
|
|
ReadBufferOperation *read_op = (ReadBufferOperation *)op;
|
|
|
|
|
MemoryProxy *memproxy = read_op->getMemoryProxy();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-06 17:49:09 +01:00
|
|
|
if (memproxy->getExecutor() == nullptr) {
|
2014-04-15 16:06:12 +02:00
|
|
|
ExecutionGroup *group = make_group(memproxy->getWriteBufferOperation());
|
|
|
|
|
memproxy->setExecutor(group);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|