Compositor: Disabled debug assert checks for connected input sockets after convertToO...
[blender.git] / source / blender / compositor / intern / COM_ExecutionSystem.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor: 
19  *              Jeroen Bakker 
20  *              Monique Dewanchand
21  */
22
23 #include "COM_ExecutionSystem.h"
24
25 #include <sstream>
26
27 #include "PIL_time.h"
28 #include "BLI_utildefines.h"
29 #include "BKE_node.h"
30
31 #include "COM_Converter.h"
32 #include "COM_NodeOperation.h"
33 #include "COM_ExecutionGroup.h"
34 #include "COM_NodeBase.h"
35 #include "COM_WorkScheduler.h"
36 #include "COM_ReadBufferOperation.h"
37 #include "COM_GroupNode.h"
38 #include "COM_WriteBufferOperation.h"
39 #include "COM_ReadBufferOperation.h"
40 #include "COM_ExecutionSystemHelper.h"
41
42 #include "BKE_global.h"
43
44 #ifdef WITH_CXX_GUARDEDALLOC
45 #include "MEM_guardedalloc.h"
46 #endif
47
48 ExecutionSystem::ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool rendering, bool fastcalculation,
49                                  const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
50 {
51         this->m_context.setbNodeTree(editingtree);
52         this->m_context.setFastCalculation(fastcalculation);
53         bNode *gnode;
54         for (gnode = (bNode *)editingtree->nodes.first; gnode; gnode = gnode->next) {
55                 if (gnode->type == NODE_GROUP && gnode->typeinfo->group_edit_get(gnode)) {
56                         this->m_context.setActivegNode(gnode);
57                         break;
58                 }
59         }
60
61         /* initialize the CompositorContext */
62         if (rendering) {
63                 this->m_context.setQuality((CompositorQuality)editingtree->render_quality);
64         }
65         else {
66                 this->m_context.setQuality((CompositorQuality)editingtree->edit_quality);
67         }
68         this->m_context.setRendering(rendering);
69         this->m_context.setHasActiveOpenCLDevices(WorkScheduler::hasGPUDevices() && (editingtree->flag & NTREE_COM_OPENCL));
70
71         ExecutionSystemHelper::addbNodeTree(*this, 0, editingtree, NULL);
72
73         this->m_context.setRenderData(rd);
74         this->m_context.setViewSettings(viewSettings);
75         this->m_context.setDisplaySettings(displaySettings);
76
77         this->convertToOperations();
78         this->groupOperations(); /* group operations in ExecutionGroups */
79         unsigned int index;
80         unsigned int resolution[2];
81         for (index = 0; index < this->m_groups.size(); index++) {
82                 resolution[0] = 0;
83                 resolution[1] = 0;
84                 ExecutionGroup *executionGroup = this->m_groups[index];
85                 executionGroup->determineResolution(resolution);
86         }
87
88 #ifdef COM_DEBUG
89         ExecutionSystemHelper::debugDump(this);
90 #endif
91 }
92
93 ExecutionSystem::~ExecutionSystem()
94 {
95         unsigned int index;
96         for (index = 0; index < this->m_connections.size(); index++) {
97                 SocketConnection *connection = this->m_connections[index];
98                 delete connection;
99         }
100         this->m_connections.clear();
101         for (index = 0; index < this->m_nodes.size(); index++) {
102                 Node *node = this->m_nodes[index];
103                 delete node;
104         }
105         this->m_nodes.clear();
106         for (index = 0; index < this->m_operations.size(); index++) {
107                 NodeOperation *operation = this->m_operations[index];
108                 delete operation;
109         }
110         this->m_operations.clear();
111         for (index = 0; index < this->m_groups.size(); index++) {
112                 ExecutionGroup *group = this->m_groups[index];
113                 delete group;
114         }
115         this->m_groups.clear();
116 }
117
118 void ExecutionSystem::execute()
119 {
120         unsigned int order = 0;
121         for (vector<NodeOperation *>::iterator iter = this->m_operations.begin(); iter != this->m_operations.end(); ++iter) {
122                 NodeBase *node = *iter;
123                 NodeOperation *operation = (NodeOperation *) node;
124                 if (operation->isReadBufferOperation()) {
125                         ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
126                         readOperation->setOffset(order);
127                         order++;
128                 }
129         }
130         unsigned int index;
131
132         for (index = 0; index < this->m_operations.size(); index++) {
133                 NodeOperation *operation = this->m_operations[index];
134                 operation->setbNodeTree(this->m_context.getbNodeTree());
135                 operation->initExecution();
136         }
137         for (index = 0; index < this->m_operations.size(); index++) {
138                 NodeOperation *operation = this->m_operations[index];
139                 if (operation->isReadBufferOperation()) {
140                         ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
141                         readOperation->updateMemoryBuffer();
142                 }
143         }
144         for (index = 0; index < this->m_groups.size(); index++) {
145                 ExecutionGroup *executionGroup = this->m_groups[index];
146                 executionGroup->setChunksize(this->m_context.getChunksize());
147                 executionGroup->initExecution();
148         }
149
150         WorkScheduler::start(this->m_context);
151
152         executeGroups(COM_PRIORITY_HIGH);
153         if (!this->getContext().isFastCalculation()) {
154                 executeGroups(COM_PRIORITY_MEDIUM);
155                 executeGroups(COM_PRIORITY_LOW);
156         }
157
158         WorkScheduler::finish();
159         WorkScheduler::stop();
160
161         for (index = 0; index < this->m_operations.size(); index++) {
162                 NodeOperation *operation = this->m_operations[index];
163                 operation->deinitExecution();
164         }
165         for (index = 0; index < this->m_groups.size(); index++) {
166                 ExecutionGroup *executionGroup = this->m_groups[index];
167                 executionGroup->deinitExecution();
168         }
169 }
170
171 void ExecutionSystem::executeGroups(CompositorPriority priority)
172 {
173         unsigned int index;
174         vector<ExecutionGroup *> executionGroups;
175         this->findOutputExecutionGroup(&executionGroups, priority);
176
177         for (index = 0; index < executionGroups.size(); index++) {
178                 ExecutionGroup *group = executionGroups[index];
179                 group->execute(this);
180         }
181 }
182
183 void ExecutionSystem::addOperation(NodeOperation *operation)
184 {
185         ExecutionSystemHelper::addOperation(this->m_operations, operation);
186 //      operation->setBTree
187 }
188
189 void ExecutionSystem::addReadWriteBufferOperations(NodeOperation *operation)
190 {
191         // for every input add write and read operation if input is not a read operation
192         // only add read operation to other links when they are attached to buffered operations.
193         unsigned int index;
194         for (index = 0; index < operation->getNumberOfInputSockets(); index++) {
195                 InputSocket *inputsocket = operation->getInputSocket(index);
196                 if (inputsocket->isConnected()) {
197                         SocketConnection *connection = inputsocket->getConnection();
198                         NodeOperation *otherEnd = (NodeOperation *)connection->getFromNode();
199                         if (!otherEnd->isReadBufferOperation()) {
200                                 // check of other end already has write operation
201                                 OutputSocket *fromsocket = connection->getFromSocket();
202                                 WriteBufferOperation *writeoperation = fromsocket->findAttachedWriteBufferOperation();
203                                 if (writeoperation == NULL) {
204                                         writeoperation = new WriteBufferOperation();
205                                         writeoperation->setbNodeTree(this->getContext().getbNodeTree());
206                                         this->addOperation(writeoperation);
207                                         ExecutionSystemHelper::addLink(this->getConnections(), fromsocket, writeoperation->getInputSocket(0));
208                                         writeoperation->readResolutionFromInputSocket();
209                                 }
210                                 ReadBufferOperation *readoperation = new ReadBufferOperation();
211                                 readoperation->setMemoryProxy(writeoperation->getMemoryProxy());
212                                 connection->setFromSocket(readoperation->getOutputSocket());
213                                 readoperation->getOutputSocket()->addConnection(connection);
214                                 readoperation->readResolutionFromWriteBuffer();
215                                 this->addOperation(readoperation);
216                         }
217                 }
218         }
219         /*
220          * link the outputsocket to a write operation
221          * link the writeoperation to a read operation
222          * link the read operation to the next node.
223          */
224         OutputSocket *outputsocket = operation->getOutputSocket();
225         if (outputsocket->isConnected()) {
226                 WriteBufferOperation *writeOperation;
227                 writeOperation = new WriteBufferOperation();
228                 writeOperation->setbNodeTree(this->getContext().getbNodeTree());
229                 this->addOperation(writeOperation);
230                 ExecutionSystemHelper::addLink(this->getConnections(), outputsocket, writeOperation->getInputSocket(0));
231                 writeOperation->readResolutionFromInputSocket();
232                 for (index = 0; index < outputsocket->getNumberOfConnections() - 1; index++) {
233                         SocketConnection *connection = outputsocket->getConnection(index);
234                         ReadBufferOperation *readoperation = new ReadBufferOperation();
235                         readoperation->setMemoryProxy(writeOperation->getMemoryProxy());
236                         connection->setFromSocket(readoperation->getOutputSocket());
237                         readoperation->getOutputSocket()->addConnection(connection);
238                         readoperation->readResolutionFromWriteBuffer();
239                         this->addOperation(readoperation);
240                 }
241         }
242 }
243
244 #ifndef NDEBUG
245 /* if this fails, there are still connection to/from this node,
246  * which have not been properly relinked to operations!
247  */
248 static void debug_check_node_connections(Node *node)
249 {
250         /* note: connected inputs are not checked here,
251          * it would break quite a lot and such inputs are ignored later anyway
252          */
253 #if 0
254         for (int i = 0; i < node->getNumberOfInputSockets(); ++i) {
255                 BLI_assert(!node->getInputSocket(i)->isConnected());
256         }
257 #endif
258         for (int i = 0; i < node->getNumberOfOutputSockets(); ++i) {
259                 BLI_assert(!node->getOutputSocket(i)->isConnected());
260         }
261 }
262 #else
263 /* stub */
264 #define debug_check_node_connections(node)
265 #endif
266
267 void ExecutionSystem::convertToOperations()
268 {
269         unsigned int index;
270         for (index = 0; index < this->m_nodes.size(); index++) {
271                 Node *node = (Node *)this->m_nodes[index];
272                 node->convertToOperations(this, &this->m_context);
273
274                 debug_check_node_connections(node);
275         }
276
277         for (index = 0; index < this->m_connections.size(); index++) {
278                 SocketConnection *connection = this->m_connections[index];
279                 if (connection->isValid()) {
280                         if (connection->getFromSocket()->getDataType() != connection->getToSocket()->getDataType()) {
281                                 Converter::convertDataType(connection, this);
282                         }
283                 }
284         }
285
286         // determine all resolutions of the operations (Width/Height)
287         for (index = 0; index < this->m_operations.size(); index++) {
288                 NodeOperation *operation = this->m_operations[index];
289                 if (operation->isOutputOperation(this->m_context.isRendering()) && !operation->isPreviewOperation()) {
290                         unsigned int resolution[2] = {0, 0};
291                         unsigned int preferredResolution[2] = {0, 0};
292                         operation->determineResolution(resolution, preferredResolution);
293                         operation->setResolution(resolution);
294                 }
295         }
296         for (index = 0; index < this->m_operations.size(); index++) {
297                 NodeOperation *operation = this->m_operations[index];
298                 if (operation->isOutputOperation(this->m_context.isRendering()) && operation->isPreviewOperation()) {
299                         unsigned int resolution[2] = {0, 0};
300                         unsigned int preferredResolution[2] = {0, 0};
301                         operation->determineResolution(resolution, preferredResolution);
302                         operation->setResolution(resolution);
303                 }
304         }
305
306         // add convert resolution operations when needed.
307         for (index = 0; index < this->m_connections.size(); index++) {
308                 SocketConnection *connection = this->m_connections[index];
309                 if (connection->isValid()) {
310                         if (connection->needsResolutionConversion()) {
311                                 Converter::convertResolution(connection, this);
312                         }
313                 }
314         }
315 }
316
317 void ExecutionSystem::groupOperations()
318 {
319         vector<NodeOperation *> outputOperations;
320         NodeOperation *operation;
321         unsigned int index;
322         // surround complex operations with ReadBufferOperation and WriteBufferOperation
323         for (index = 0; index < this->m_operations.size(); index++) {
324                 operation = this->m_operations[index];
325                 if (operation->isComplex()) {
326                         this->addReadWriteBufferOperations(operation);
327                 }
328         }
329         ExecutionSystemHelper::findOutputNodeOperations(&outputOperations, this->getOperations(), this->m_context.isRendering());
330         for (vector<NodeOperation *>::iterator iter = outputOperations.begin(); iter != outputOperations.end(); ++iter) {
331                 operation = *iter;
332                 ExecutionGroup *group = new ExecutionGroup();
333                 group->addOperation(this, operation);
334                 group->setOutputExecutionGroup(true);
335                 ExecutionSystemHelper::addExecutionGroup(this->getExecutionGroups(), group);
336         }
337 }
338
339 void ExecutionSystem::addSocketConnection(SocketConnection *connection)
340 {
341         this->m_connections.push_back(connection);
342 }
343
344 void ExecutionSystem::removeSocketConnection(SocketConnection *connection)
345 {
346         for (vector<SocketConnection *>::iterator it = m_connections.begin(); it != m_connections.end(); ++it) {
347                 if (*it == connection) {
348                         this->m_connections.erase(it);
349                         return;
350                 }
351         }
352 }
353
354
355 void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result, CompositorPriority priority) const
356 {
357         unsigned int index;
358         for (index = 0; index < this->m_groups.size(); index++) {
359                 ExecutionGroup *group = this->m_groups[index];
360                 if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) {
361                         result->push_back(group);
362                 }
363         }
364 }
365
366 void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result) const
367 {
368         unsigned int index;
369         for (index = 0; index < this->m_groups.size(); index++) {
370                 ExecutionGroup *group = this->m_groups[index];
371                 if (group->isOutputExecutionGroup()) {
372                         result->push_back(group);
373                 }
374         }
375 }