c6e0f6c2cfbf0508e628eb193118a37afff5f886
[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         for (int i = 0; i < node->getNumberOfInputSockets(); ++i) {
251                 BLI_assert(!node->getInputSocket(i)->isConnected());
252         }
253         for (int i = 0; i < node->getNumberOfOutputSockets(); ++i) {
254                 BLI_assert(!node->getOutputSocket(i)->isConnected());
255         }
256 }
257 #else
258 /* stub */
259 #define debug_check_node_connections(node)
260 #endif
261
262 void ExecutionSystem::convertToOperations()
263 {
264         unsigned int index;
265         for (index = 0; index < this->m_nodes.size(); index++) {
266                 Node *node = (Node *)this->m_nodes[index];
267                 node->convertToOperations(this, &this->m_context);
268
269                 debug_check_node_connections(node);
270         }
271
272         for (index = 0; index < this->m_connections.size(); index++) {
273                 SocketConnection *connection = this->m_connections[index];
274                 if (connection->isValid()) {
275                         if (connection->getFromSocket()->getDataType() != connection->getToSocket()->getDataType()) {
276                                 Converter::convertDataType(connection, this);
277                         }
278                 }
279         }
280
281         // determine all resolutions of the operations (Width/Height)
282         for (index = 0; index < this->m_operations.size(); index++) {
283                 NodeOperation *operation = this->m_operations[index];
284                 if (operation->isOutputOperation(this->m_context.isRendering()) && !operation->isPreviewOperation()) {
285                         unsigned int resolution[2] = {0, 0};
286                         unsigned int preferredResolution[2] = {0, 0};
287                         operation->determineResolution(resolution, preferredResolution);
288                         operation->setResolution(resolution);
289                 }
290         }
291         for (index = 0; index < this->m_operations.size(); index++) {
292                 NodeOperation *operation = this->m_operations[index];
293                 if (operation->isOutputOperation(this->m_context.isRendering()) && operation->isPreviewOperation()) {
294                         unsigned int resolution[2] = {0, 0};
295                         unsigned int preferredResolution[2] = {0, 0};
296                         operation->determineResolution(resolution, preferredResolution);
297                         operation->setResolution(resolution);
298                 }
299         }
300
301         // add convert resolution operations when needed.
302         for (index = 0; index < this->m_connections.size(); index++) {
303                 SocketConnection *connection = this->m_connections[index];
304                 if (connection->isValid()) {
305                         if (connection->needsResolutionConversion()) {
306                                 Converter::convertResolution(connection, this);
307                         }
308                 }
309         }
310 }
311
312 void ExecutionSystem::groupOperations()
313 {
314         vector<NodeOperation *> outputOperations;
315         NodeOperation *operation;
316         unsigned int index;
317         // surround complex operations with ReadBufferOperation and WriteBufferOperation
318         for (index = 0; index < this->m_operations.size(); index++) {
319                 operation = this->m_operations[index];
320                 if (operation->isComplex()) {
321                         this->addReadWriteBufferOperations(operation);
322                 }
323         }
324         ExecutionSystemHelper::findOutputNodeOperations(&outputOperations, this->getOperations(), this->m_context.isRendering());
325         for (vector<NodeOperation *>::iterator iter = outputOperations.begin(); iter != outputOperations.end(); ++iter) {
326                 operation = *iter;
327                 ExecutionGroup *group = new ExecutionGroup();
328                 group->addOperation(this, operation);
329                 group->setOutputExecutionGroup(true);
330                 ExecutionSystemHelper::addExecutionGroup(this->getExecutionGroups(), group);
331         }
332 }
333
334 void ExecutionSystem::addSocketConnection(SocketConnection *connection)
335 {
336         this->m_connections.push_back(connection);
337 }
338
339 void ExecutionSystem::removeSocketConnection(SocketConnection *connection)
340 {
341         for (vector<SocketConnection *>::iterator it = m_connections.begin(); it != m_connections.end(); ++it) {
342                 if (*it == connection) {
343                         this->m_connections.erase(it);
344                         return;
345                 }
346         }
347 }
348
349
350 void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result, CompositorPriority priority) const
351 {
352         unsigned int index;
353         for (index = 0; index < this->m_groups.size(); index++) {
354                 ExecutionGroup *group = this->m_groups[index];
355                 if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) {
356                         result->push_back(group);
357                 }
358         }
359 }
360
361 void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result) const
362 {
363         unsigned int index;
364         for (index = 0; index < this->m_groups.size(); index++) {
365                 ExecutionGroup *group = this->m_groups[index];
366                 if (group->isOutputExecutionGroup()) {
367                         result->push_back(group);
368                 }
369         }
370 }