Fix for #34739 and #35060, avoid ambiguity in compositor viewer nodes.
[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 extern "C" {
30 #include "BKE_node.h"
31 }
32
33 #include "COM_Converter.h"
34 #include "COM_NodeOperation.h"
35 #include "COM_ExecutionGroup.h"
36 #include "COM_NodeBase.h"
37 #include "COM_WorkScheduler.h"
38 #include "COM_ReadBufferOperation.h"
39 #include "COM_GroupNode.h"
40 #include "COM_WriteBufferOperation.h"
41 #include "COM_ReadBufferOperation.h"
42 #include "COM_ExecutionSystemHelper.h"
43
44 #include "BKE_global.h"
45
46 #ifdef WITH_CXX_GUARDEDALLOC
47 #include "MEM_guardedalloc.h"
48 #endif
49
50 ExecutionSystem::ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool rendering, bool fastcalculation,
51                                  const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
52 {
53         this->m_context.setbNodeTree(editingtree);
54         this->m_context.setPreviewHash(editingtree->previews);
55         this->m_context.setFastCalculation(fastcalculation);
56         /* initialize the CompositorContext */
57         if (rendering) {
58                 this->m_context.setQuality((CompositorQuality)editingtree->render_quality);
59         }
60         else {
61                 this->m_context.setQuality((CompositorQuality)editingtree->edit_quality);
62         }
63         this->m_context.setRendering(rendering);
64         this->m_context.setHasActiveOpenCLDevices(WorkScheduler::hasGPUDevices() && (editingtree->flag & NTREE_COM_OPENCL));
65
66         ExecutionSystemHelper::addbNodeTree(*this, 0, editingtree, NODE_INSTANCE_KEY_BASE);
67
68         this->m_context.setRenderData(rd);
69         this->m_context.setViewSettings(viewSettings);
70         this->m_context.setDisplaySettings(displaySettings);
71
72         this->convertToOperations();
73         this->groupOperations(); /* group operations in ExecutionGroups */
74         unsigned int index;
75         unsigned int resolution[2];
76
77         rctf *viewer_border = &editingtree->viewer_border;
78         bool use_viewer_border = (editingtree->flag & NTREE_VIEWER_BORDER) &&
79                                  viewer_border->xmin < viewer_border->xmax &&
80                                  viewer_border->ymin < viewer_border->ymax;
81
82         for (index = 0; index < this->m_groups.size(); index++) {
83                 resolution[0] = 0;
84                 resolution[1] = 0;
85                 ExecutionGroup *executionGroup = this->m_groups[index];
86                 executionGroup->determineResolution(resolution);
87
88                 if (rendering) {
89                         /* case when cropping to render border happens is handled in
90                          * compositor output and render layer nodes
91                          */
92                         if ((rd->mode & R_BORDER) && !(rd->mode & R_CROP)) {
93                                 executionGroup->setRenderBorder(rd->border.xmin, rd->border.xmax,
94                                                                 rd->border.ymin, rd->border.ymax);
95                         }
96                 }
97
98                 if (use_viewer_border) {
99                         executionGroup->setViewerBorder(viewer_border->xmin, viewer_border->xmax,
100                                                         viewer_border->ymin, viewer_border->ymax);
101                 }
102         }
103
104 #ifdef COM_DEBUG
105         ExecutionSystemHelper::debugDump(this);
106 #endif
107 }
108
109 ExecutionSystem::~ExecutionSystem()
110 {
111         unsigned int index;
112         for (index = 0; index < this->m_connections.size(); index++) {
113                 SocketConnection *connection = this->m_connections[index];
114                 delete connection;
115         }
116         this->m_connections.clear();
117         for (index = 0; index < this->m_nodes.size(); index++) {
118                 Node *node = this->m_nodes[index];
119                 delete node;
120         }
121         this->m_nodes.clear();
122         for (index = 0; index < this->m_operations.size(); index++) {
123                 NodeOperation *operation = this->m_operations[index];
124                 delete operation;
125         }
126         this->m_operations.clear();
127         for (index = 0; index < this->m_groups.size(); index++) {
128                 ExecutionGroup *group = this->m_groups[index];
129                 delete group;
130         }
131         this->m_groups.clear();
132 }
133
134 void ExecutionSystem::execute()
135 {
136         unsigned int order = 0;
137         for (vector<NodeOperation *>::iterator iter = this->m_operations.begin(); iter != this->m_operations.end(); ++iter) {
138                 NodeBase *node = *iter;
139                 NodeOperation *operation = (NodeOperation *) node;
140                 if (operation->isReadBufferOperation()) {
141                         ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
142                         readOperation->setOffset(order);
143                         order++;
144                 }
145         }
146         unsigned int index;
147
148         for (index = 0; index < this->m_operations.size(); index++) {
149                 NodeOperation *operation = this->m_operations[index];
150                 operation->setbNodeTree(this->m_context.getbNodeTree());
151                 operation->initExecution();
152         }
153         for (index = 0; index < this->m_operations.size(); index++) {
154                 NodeOperation *operation = this->m_operations[index];
155                 if (operation->isReadBufferOperation()) {
156                         ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
157                         readOperation->updateMemoryBuffer();
158                 }
159         }
160         for (index = 0; index < this->m_groups.size(); index++) {
161                 ExecutionGroup *executionGroup = this->m_groups[index];
162                 executionGroup->setChunksize(this->m_context.getChunksize());
163                 executionGroup->initExecution();
164         }
165
166         WorkScheduler::start(this->m_context);
167
168         executeGroups(COM_PRIORITY_HIGH);
169         if (!this->getContext().isFastCalculation()) {
170                 executeGroups(COM_PRIORITY_MEDIUM);
171                 executeGroups(COM_PRIORITY_LOW);
172         }
173
174         WorkScheduler::finish();
175         WorkScheduler::stop();
176
177         for (index = 0; index < this->m_operations.size(); index++) {
178                 NodeOperation *operation = this->m_operations[index];
179                 operation->deinitExecution();
180         }
181         for (index = 0; index < this->m_groups.size(); index++) {
182                 ExecutionGroup *executionGroup = this->m_groups[index];
183                 executionGroup->deinitExecution();
184         }
185 }
186
187 void ExecutionSystem::executeGroups(CompositorPriority priority)
188 {
189         unsigned int index;
190         vector<ExecutionGroup *> executionGroups;
191         this->findOutputExecutionGroup(&executionGroups, priority);
192
193         for (index = 0; index < executionGroups.size(); index++) {
194                 ExecutionGroup *group = executionGroups[index];
195                 group->execute(this);
196         }
197 }
198
199 void ExecutionSystem::addOperation(NodeOperation *operation)
200 {
201         ExecutionSystemHelper::addOperation(this->m_operations, operation);
202 //      operation->setBTree
203 }
204
205 void ExecutionSystem::addReadWriteBufferOperations(NodeOperation *operation)
206 {
207         // for every input add write and read operation if input is not a read operation
208         // only add read operation to other links when they are attached to buffered operations.
209         unsigned int index;
210         for (index = 0; index < operation->getNumberOfInputSockets(); index++) {
211                 InputSocket *inputsocket = operation->getInputSocket(index);
212                 if (inputsocket->isConnected()) {
213                         SocketConnection *connection = inputsocket->getConnection();
214                         NodeOperation *otherEnd = (NodeOperation *)connection->getFromNode();
215                         if (!otherEnd->isReadBufferOperation()) {
216                                 // check of other end already has write operation
217                                 OutputSocket *fromsocket = connection->getFromSocket();
218                                 WriteBufferOperation *writeoperation = fromsocket->findAttachedWriteBufferOperation();
219                                 if (writeoperation == NULL) {
220                                         writeoperation = new WriteBufferOperation();
221                                         writeoperation->setbNodeTree(this->getContext().getbNodeTree());
222                                         this->addOperation(writeoperation);
223                                         ExecutionSystemHelper::addLink(this->getConnections(), fromsocket, writeoperation->getInputSocket(0));
224                                         writeoperation->readResolutionFromInputSocket();
225                                 }
226                                 ReadBufferOperation *readoperation = new ReadBufferOperation();
227                                 readoperation->setMemoryProxy(writeoperation->getMemoryProxy());
228                                 connection->setFromSocket(readoperation->getOutputSocket());
229                                 readoperation->getOutputSocket()->addConnection(connection);
230                                 readoperation->readResolutionFromWriteBuffer();
231                                 this->addOperation(readoperation);
232                         }
233                 }
234         }
235         /*
236          * link the outputsocket to a write operation
237          * link the writeoperation to a read operation
238          * link the read operation to the next node.
239          */
240         OutputSocket *outputsocket = operation->getOutputSocket();
241         if (outputsocket->isConnected()) {
242                 WriteBufferOperation *writeOperation;
243                 writeOperation = new WriteBufferOperation();
244                 writeOperation->setbNodeTree(this->getContext().getbNodeTree());
245                 this->addOperation(writeOperation);
246                 ExecutionSystemHelper::addLink(this->getConnections(), outputsocket, writeOperation->getInputSocket(0));
247                 writeOperation->readResolutionFromInputSocket();
248                 for (index = 0; index < outputsocket->getNumberOfConnections() - 1; index++) {
249                         SocketConnection *connection = outputsocket->getConnection(index);
250                         ReadBufferOperation *readoperation = new ReadBufferOperation();
251                         readoperation->setMemoryProxy(writeOperation->getMemoryProxy());
252                         connection->setFromSocket(readoperation->getOutputSocket());
253                         readoperation->getOutputSocket()->addConnection(connection);
254                         readoperation->readResolutionFromWriteBuffer();
255                         this->addOperation(readoperation);
256                 }
257         }
258 }
259
260 #ifndef NDEBUG
261 /* if this fails, there are still connection to/from this node,
262  * which have not been properly relinked to operations!
263  */
264 static void debug_check_node_connections(Node *node)
265 {
266         /* note: connected inputs are not checked here,
267          * it would break quite a lot and such inputs are ignored later anyway
268          */
269 #if 0
270         for (int i = 0; i < node->getNumberOfInputSockets(); ++i) {
271                 BLI_assert(!node->getInputSocket(i)->isConnected());
272         }
273 #endif
274         for (int i = 0; i < node->getNumberOfOutputSockets(); ++i) {
275                 BLI_assert(!node->getOutputSocket(i)->isConnected());
276         }
277 }
278 #else
279 /* stub */
280 #define debug_check_node_connections(node)
281 #endif
282
283 void ExecutionSystem::convertToOperations()
284 {
285         unsigned int index;
286         for (index = 0; index < this->m_nodes.size(); index++) {
287                 Node *node = (Node *)this->m_nodes[index];
288                 node->convertToOperations(this, &this->m_context);
289
290                 debug_check_node_connections(node);
291         }
292
293         for (index = 0; index < this->m_connections.size(); index++) {
294                 SocketConnection *connection = this->m_connections[index];
295                 if (connection->isValid()) {
296                         if (connection->getFromSocket()->getDataType() != connection->getToSocket()->getDataType()) {
297                                 Converter::convertDataType(connection, this);
298                         }
299                 }
300         }
301
302         // determine all resolutions of the operations (Width/Height)
303         for (index = 0; index < this->m_operations.size(); index++) {
304                 NodeOperation *operation = this->m_operations[index];
305                 if (operation->isOutputOperation(this->m_context.isRendering()) && !operation->isPreviewOperation()) {
306                         unsigned int resolution[2] = {0, 0};
307                         unsigned int preferredResolution[2] = {0, 0};
308                         operation->determineResolution(resolution, preferredResolution);
309                         operation->setResolution(resolution);
310                 }
311         }
312         for (index = 0; index < this->m_operations.size(); index++) {
313                 NodeOperation *operation = this->m_operations[index];
314                 if (operation->isOutputOperation(this->m_context.isRendering()) && operation->isPreviewOperation()) {
315                         unsigned int resolution[2] = {0, 0};
316                         unsigned int preferredResolution[2] = {0, 0};
317                         operation->determineResolution(resolution, preferredResolution);
318                         operation->setResolution(resolution);
319                 }
320         }
321
322         // add convert resolution operations when needed.
323         for (index = 0; index < this->m_connections.size(); index++) {
324                 SocketConnection *connection = this->m_connections[index];
325                 if (connection->isValid()) {
326                         if (connection->needsResolutionConversion()) {
327                                 Converter::convertResolution(connection, this);
328                         }
329                 }
330         }
331 }
332
333 void ExecutionSystem::groupOperations()
334 {
335         vector<NodeOperation *> outputOperations;
336         NodeOperation *operation;
337         unsigned int index;
338         // surround complex operations with ReadBufferOperation and WriteBufferOperation
339         for (index = 0; index < this->m_operations.size(); index++) {
340                 operation = this->m_operations[index];
341                 if (operation->isComplex()) {
342                         this->addReadWriteBufferOperations(operation);
343                 }
344         }
345         ExecutionSystemHelper::findOutputNodeOperations(&outputOperations, this->getOperations(), this->m_context.isRendering());
346         for (vector<NodeOperation *>::iterator iter = outputOperations.begin(); iter != outputOperations.end(); ++iter) {
347                 operation = *iter;
348                 ExecutionGroup *group = new ExecutionGroup();
349                 group->addOperation(this, operation);
350                 group->setOutputExecutionGroup(true);
351                 ExecutionSystemHelper::addExecutionGroup(this->getExecutionGroups(), group);
352         }
353 }
354
355 void ExecutionSystem::addSocketConnection(SocketConnection *connection)
356 {
357         this->m_connections.push_back(connection);
358 }
359
360 void ExecutionSystem::removeSocketConnection(SocketConnection *connection)
361 {
362         for (vector<SocketConnection *>::iterator it = m_connections.begin(); it != m_connections.end(); ++it) {
363                 if (*it == connection) {
364                         this->m_connections.erase(it);
365                         return;
366                 }
367         }
368 }
369
370
371 void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result, CompositorPriority priority) const
372 {
373         unsigned int index;
374         for (index = 0; index < this->m_groups.size(); index++) {
375                 ExecutionGroup *group = this->m_groups[index];
376                 if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) {
377                         result->push_back(group);
378                 }
379         }
380 }
381
382 void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result) const
383 {
384         unsigned int index;
385         for (index = 0; index < this->m_groups.size(); index++) {
386                 ExecutionGroup *group = this->m_groups[index];
387                 if (group->isOutputExecutionGroup()) {
388                         result->push_back(group);
389                 }
390         }
391 }