9a80c5e82aedebf6565ed34dc36f944b85e24036
[blender.git] / source / blender / compositor / intern / COM_ExecutionGroup.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 <algorithm>
24 #include <math.h>
25 #include <sstream>
26 #include <stdlib.h>
27
28 #include "COM_ExecutionGroup.h"
29 #include "COM_InputSocket.h"
30 #include "COM_SocketConnection.h"
31 #include "COM_defines.h"
32 #include "COM_ExecutionSystem.h"
33 #include "COM_ReadBufferOperation.h"
34 #include "COM_WriteBufferOperation.h"
35 #include "COM_ReadBufferOperation.h"
36 #include "COM_WorkScheduler.h"
37 #include "COM_ViewerOperation.h"
38 #include "COM_ChunkOrder.h"
39 #include "COM_ExecutionSystemHelper.h"
40
41 #include "BLI_math.h"
42 #include "PIL_time.h"
43 #include "WM_api.h"
44 #include "WM_types.h"
45
46 ExecutionGroup::ExecutionGroup()
47 {
48         this->m_isOutput = false;
49         this->m_complex = false;
50         this->m_chunkExecutionStates = NULL;
51         this->m_bTree = NULL;
52         this->m_height = 0;
53         this->m_width = 0;
54         this->m_cachedMaxReadBufferOffset = 0;
55         this->m_numberOfXChunks = 0;
56         this->m_numberOfYChunks = 0;
57         this->m_numberOfChunks = 0;
58         this->m_initialized = false;
59         this->m_openCL = false;
60         this->m_singleThreaded = false;
61         this->m_chunksFinished = 0;
62 }
63
64 CompositorPriority ExecutionGroup::getRenderPriotrity()
65 {
66         return this->getOutputNodeOperation()->getRenderPriority();
67 }
68
69 bool ExecutionGroup::containsOperation(NodeOperation *operation)
70 {
71         for (vector<NodeOperation *>::const_iterator iterator = this->m_operations.begin(); iterator != this->m_operations.end(); ++iterator) {
72                 NodeOperation *inListOperation = *iterator;
73                 if (inListOperation == operation) {
74                         return true;
75                 }
76         }
77         return false;
78 }
79
80 const bool ExecutionGroup::isComplex() const
81 {
82         return this->m_complex;
83 }
84
85 bool ExecutionGroup::canContainOperation(NodeOperation *operation)
86 {
87         if (!this->m_initialized) { return true; }
88         if (operation->isReadBufferOperation()) { return true; }
89         if (operation->isWriteBufferOperation()) { return false; }
90         if (operation->isSetOperation()) { return true; }
91
92         if (!this->isComplex()) {
93                 return (!operation->isComplex());
94         }
95         else {
96                 return false;
97         }
98 }
99
100 void ExecutionGroup::addOperation(ExecutionSystem *system, NodeOperation *operation)
101 {
102         /* should never happen but in rare cases it can - it causes confusing crashes */
103         BLI_assert(operation->isOperation() == true);
104
105         if (containsOperation(operation)) return;
106         if (canContainOperation(operation)) {
107                 if (!operation->isBufferOperation()) {
108                         this->m_complex = operation->isComplex();
109                         this->m_openCL = operation->isOpenCL();
110                         this->m_singleThreaded = operation->isSingleThreaded();
111                         this->m_initialized = true;
112                 }
113                 this->m_operations.push_back(operation);
114                 if (operation->isReadBufferOperation()) {
115                         ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
116                         WriteBufferOperation *writeOperation = readOperation->getMemoryProxy()->getWriteBufferOperation();
117                         this->addOperation(system, writeOperation);
118                 }
119                 else {
120                         unsigned int index;
121                         for (index = 0; index < operation->getNumberOfInputSockets(); index++) {
122                                 InputSocket *inputSocket = operation->getInputSocket(index);
123                                 if (inputSocket->isConnected()) {
124                                         NodeOperation *node = (NodeOperation *)inputSocket->getConnection()->getFromNode();
125                                         this->addOperation(system, node);
126                                 }
127                         }
128                 }
129         }
130         else {
131                 if (operation->isWriteBufferOperation()) {
132                         WriteBufferOperation *writeoperation = (WriteBufferOperation *)operation;
133                         if (writeoperation->getMemoryProxy()->getExecutor() == NULL) {
134                                 ExecutionGroup *newGroup = new ExecutionGroup();
135                                 writeoperation->getMemoryProxy()->setExecutor(newGroup);
136                                 newGroup->addOperation(system, operation);
137                                 ExecutionSystemHelper::addExecutionGroup(system->getExecutionGroups(), newGroup);
138                         }
139                 }
140         }
141 }
142
143 NodeOperation *ExecutionGroup::getOutputNodeOperation() const
144 {
145         return this->m_operations[0]; // the first operation of the group is always the output operation.
146 }
147
148 void ExecutionGroup::initExecution()
149 {
150         if (this->m_chunkExecutionStates != NULL) {
151                 delete[] this->m_chunkExecutionStates;
152         }
153         unsigned int index;
154         determineNumberOfChunks();
155
156         this->m_chunkExecutionStates = NULL;
157         if (this->m_numberOfChunks != 0) {
158                 this->m_chunkExecutionStates = new ChunkExecutionState[this->m_numberOfChunks];
159                 for (index = 0; index < this->m_numberOfChunks; index++) {
160                         this->m_chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED;
161                 }
162         }
163
164
165         unsigned int maxNumber = 0;
166
167         for (index = 0; index < this->m_operations.size(); index++) {
168                 NodeOperation *operation = this->m_operations[index];
169                 if (operation->isReadBufferOperation()) {
170                         ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
171                         this->m_cachedReadOperations.push_back(readOperation);
172                         maxNumber = max(maxNumber, readOperation->getOffset());
173                 }
174         }
175         maxNumber++;
176         this->m_cachedMaxReadBufferOffset = maxNumber;
177
178 }
179
180 void ExecutionGroup::deinitExecution()
181 {
182         if (this->m_chunkExecutionStates != NULL) {
183                 delete[] this->m_chunkExecutionStates;
184                 this->m_chunkExecutionStates = NULL;
185         }
186         this->m_numberOfChunks = 0;
187         this->m_numberOfXChunks = 0;
188         this->m_numberOfYChunks = 0;
189         this->m_cachedReadOperations.clear();
190         this->m_bTree = NULL;
191 }
192 void ExecutionGroup::determineResolution(unsigned int resolution[2])
193 {
194         NodeOperation *operation = this->getOutputNodeOperation();
195         resolution[0] = operation->getWidth();
196         resolution[1] = operation->getHeight();
197         this->setResolution(resolution);
198 }
199
200 void ExecutionGroup::determineNumberOfChunks()
201 {
202         if (this->m_singleThreaded) {
203                 this->m_numberOfXChunks = 1;
204                 this->m_numberOfYChunks = 1;
205                 this->m_numberOfChunks = 1;
206         } 
207         else {
208                 const float chunkSizef = this->m_chunkSize;
209                 this->m_numberOfXChunks = ceil(this->m_width / chunkSizef);
210                 this->m_numberOfYChunks = ceil(this->m_height / chunkSizef);
211                 this->m_numberOfChunks = this->m_numberOfXChunks * this->m_numberOfYChunks;
212         }
213 }
214
215 /**
216  * this method is called for the top execution groups. containing the compositor node or the preview node or the viewer node)
217  */
218 void ExecutionGroup::execute(ExecutionSystem *graph)
219 {
220         CompositorContext& context = graph->getContext();
221         const bNodeTree *bTree = context.getbNodeTree();
222         if (this->m_width == 0 || this->m_height == 0) {return; } /// @note: break out... no pixels to calculate.
223         if (bTree->test_break && bTree->test_break(bTree->tbh)) {return; } /// @note: early break out for blur and preview nodes
224         if (this->m_numberOfChunks == 0) {return; } /// @note: early break out
225         unsigned int chunkNumber;
226
227         this->m_chunksFinished = 0;
228         this->m_bTree = bTree;
229         unsigned int index;
230         unsigned int *chunkOrder = new unsigned int[this->m_numberOfChunks];
231
232         for (chunkNumber = 0; chunkNumber < this->m_numberOfChunks; chunkNumber++) {
233                 chunkOrder[chunkNumber] = chunkNumber;
234         }
235         NodeOperation *operation = this->getOutputNodeOperation();
236         float centerX = 0.5;
237         float centerY = 0.5;
238         OrderOfChunks chunkorder = COM_ORDER_OF_CHUNKS_DEFAULT;
239
240         if (operation->isViewerOperation()) {
241                 ViewerBaseOperation *viewer = (ViewerBaseOperation *)operation;
242                 centerX = viewer->getCenterX();
243                 centerY = viewer->getCenterY();
244                 chunkorder = viewer->getChunkOrder();
245         }
246
247         switch (chunkorder) {
248                 case COM_TO_RANDOM:
249                         for (index = 0; index < 2 * this->m_numberOfChunks; index++) {
250                                 int index1 = rand() % this->m_numberOfChunks;
251                                 int index2 = rand() % this->m_numberOfChunks;
252                                 int s = chunkOrder[index1];
253                                 chunkOrder[index1] = chunkOrder[index2];
254                                 chunkOrder[index2] = s;
255                         }
256                         break;
257                 case COM_TO_CENTER_OUT:
258                 {
259                         ChunkOrderHotspot **hotspots = new ChunkOrderHotspot *[1];
260                         hotspots[0] = new ChunkOrderHotspot(this->m_width * centerX, this->m_height * centerY, 0.0f);
261                         rcti rect;
262                         ChunkOrder *chunkOrders = new ChunkOrder[this->m_numberOfChunks];
263                         for (index = 0; index < this->m_numberOfChunks; index++) {
264                                 determineChunkRect(&rect, index);
265                                 chunkOrders[index].setChunkNumber(index);
266                                 chunkOrders[index].setX(rect.xmin);
267                                 chunkOrders[index].setY(rect.ymin);
268                                 chunkOrders[index].determineDistance(hotspots, 1);
269                         }
270
271                         sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]);
272                         for (index = 0; index < this->m_numberOfChunks; index++) {
273                                 chunkOrder[index] = chunkOrders[index].getChunkNumber();
274                         }
275
276                         delete hotspots[0];
277                         delete[] hotspots;
278                         delete[] chunkOrders;
279                 }
280                 break;
281                 case COM_TO_RULE_OF_THIRDS:
282                 {
283                         ChunkOrderHotspot **hotspots = new ChunkOrderHotspot *[9];
284                         unsigned int tx = this->m_width / 6;
285                         unsigned int ty = this->m_height / 6;
286                         unsigned int mx = this->m_width / 2;
287                         unsigned int my = this->m_height / 2;
288                         unsigned int bx = mx + 2 * tx;
289                         unsigned int by = my + 2 * ty;
290
291                         float addition = this->m_numberOfChunks / COM_RULE_OF_THIRDS_DIVIDER;
292                         hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0);
293                         hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1);
294                         hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2);
295                         hotspots[3] = new ChunkOrderHotspot(bx, by, addition * 3);
296                         hotspots[4] = new ChunkOrderHotspot(tx, ty, addition * 4);
297                         hotspots[5] = new ChunkOrderHotspot(bx, ty, addition * 5);
298                         hotspots[6] = new ChunkOrderHotspot(tx, by, addition * 6);
299                         hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7);
300                         hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8);
301                         rcti rect;
302                         ChunkOrder *chunkOrders = new ChunkOrder[this->m_numberOfChunks];
303                         for (index = 0; index < this->m_numberOfChunks; index++) {
304                                 determineChunkRect(&rect, index);
305                                 chunkOrders[index].setChunkNumber(index);
306                                 chunkOrders[index].setX(rect.xmin);
307                                 chunkOrders[index].setY(rect.ymin);
308                                 chunkOrders[index].determineDistance(hotspots, 9);
309                         }
310
311                         sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]);
312
313                         for (index = 0; index < this->m_numberOfChunks; index++) {
314                                 chunkOrder[index] = chunkOrders[index].getChunkNumber();
315                         }
316
317                         delete hotspots[0];
318                         delete hotspots[1];
319                         delete hotspots[2];
320                         delete hotspots[3];
321                         delete hotspots[4];
322                         delete hotspots[5];
323                         delete hotspots[6];
324                         delete hotspots[7];
325                         delete hotspots[8];
326                         delete[] hotspots;
327                         delete[] chunkOrders;
328                 }
329                 break;
330                 case COM_TO_TOP_DOWN:
331                 default:
332                         break;
333         }
334
335         bool breaked = false;
336         bool finished = false;
337         unsigned int startIndex = 0;
338         const int maxNumberEvaluated = BLI_system_thread_count() * 2;
339
340         while (!finished && !breaked) {
341                 bool startEvaluated = false;
342                 finished = true;
343                 int numberEvaluated = 0;
344
345                 for (index = startIndex; index < this->m_numberOfChunks && numberEvaluated < maxNumberEvaluated; index++) {
346                         chunkNumber = chunkOrder[index];
347                         int yChunk = chunkNumber / this->m_numberOfXChunks;
348                         int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks);
349                         const ChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber];
350                         if (state == COM_ES_NOT_SCHEDULED) {
351                                 scheduleChunkWhenPossible(graph, xChunk, yChunk);
352                                 finished = false;
353                                 startEvaluated = true;
354                                 numberEvaluated++;
355
356                                 WM_main_add_notifier(NC_WINDOW | ND_DRAW, NULL);
357                         }
358                         else if (state == COM_ES_SCHEDULED) {
359                                 finished = false;
360                                 startEvaluated = true;
361                                 numberEvaluated++;
362                         }
363                         else if (state == COM_ES_EXECUTED && !startEvaluated) {
364                                 startIndex = index + 1;
365                         }
366                 }
367
368                 WorkScheduler::finish();
369
370                 if (bTree->test_break && bTree->test_break(bTree->tbh)) {
371                         breaked = true;
372                 }
373         }
374
375         delete[] chunkOrder;
376 }
377
378 MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber)
379 {
380         rcti rect;
381         vector<MemoryProxy *> memoryproxies;
382         unsigned int index;
383         determineChunkRect(&rect, chunkNumber);
384
385         this->determineDependingMemoryProxies(&memoryproxies);
386         MemoryBuffer **memoryBuffers = new MemoryBuffer *[this->m_cachedMaxReadBufferOffset];
387         for (index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
388                 memoryBuffers[index] = NULL;
389         }
390         rcti output;
391         for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
392                 ReadBufferOperation *readOperation = (ReadBufferOperation *)this->m_cachedReadOperations[index];
393                 MemoryProxy *memoryProxy = readOperation->getMemoryProxy();
394                 this->determineDependingAreaOfInterest(&rect, readOperation, &output);
395                 MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer(memoryProxy, &output);
396                 memoryBuffers[readOperation->getOffset()] = memoryBuffer;
397         }
398         return memoryBuffers;
399 }
400
401 MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, rcti *rect)
402 {
403         MemoryBuffer *imageBuffer = memoryProxy->getBuffer();
404         MemoryBuffer *result = new MemoryBuffer(memoryProxy, rect);
405         result->copyContentFrom(imageBuffer);
406         return result;
407 }
408
409 void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers)
410 {
411         if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED)
412                 this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
413         
414         this->m_chunksFinished++;
415         if (memoryBuffers) {
416                 for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
417                         MemoryBuffer *buffer = memoryBuffers[index];
418                         if (buffer) {
419                                 if (buffer->isTemporarily()) {
420                                         memoryBuffers[index] = NULL;
421                                         delete buffer;
422                                 }
423                         }
424                 }
425                 delete[] memoryBuffers;
426         }
427         if (this->m_bTree) {
428                 // status report is only performed for top level Execution Groups.
429                 float progress = this->m_chunksFinished;
430                 progress /= this->m_numberOfChunks;
431                 this->m_bTree->progress(this->m_bTree->prh, progress);
432         }
433 }
434
435 inline void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int xChunk, const unsigned int yChunk) const
436 {
437         if (this->m_singleThreaded) {
438                 BLI_rcti_init(rect, 0, this->m_width, 0, this->m_height);
439         }
440         else {
441                 const unsigned int minx = xChunk * this->m_chunkSize;
442                 const unsigned int miny = yChunk * this->m_chunkSize;
443                 BLI_rcti_init(rect, minx, min(minx + this->m_chunkSize, this->m_width), miny, min(miny + this->m_chunkSize, this->m_height));
444         }
445 }
446
447 void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const
448 {
449         const unsigned int yChunk = chunkNumber / this->m_numberOfXChunks;
450         const unsigned int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks);
451         determineChunkRect(rect, xChunk, yChunk);
452 }
453
454 MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int chunkNumber, rcti *rect)
455 {
456         // we asume that this method is only called from complex execution groups.
457         NodeOperation *operation = this->getOutputNodeOperation();
458         if (operation->isWriteBufferOperation()) {
459                 WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation;
460                 MemoryBuffer *buffer = new MemoryBuffer(writeOperation->getMemoryProxy(), rect);
461                 return buffer;
462         }
463         return NULL;
464 }
465
466
467 bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area)
468 {
469         if (this->m_singleThreaded) {
470                 return scheduleChunkWhenPossible(graph, 0, 0);
471         }
472         // find all chunks inside the rect
473         // determine minxchunk, minychunk, maxxchunk, maxychunk where x and y are chunknumbers
474
475         float chunkSizef = this->m_chunkSize;
476
477         int indexx, indexy;
478         int minxchunk = floor(area->xmin / chunkSizef);
479         int maxxchunk = ceil((area->xmax - 1) / chunkSizef);
480         int minychunk = floor(area->ymin / chunkSizef);
481         int maxychunk = ceil((area->ymax - 1) / chunkSizef);
482         minxchunk = MAX2(minxchunk, 0);
483         minychunk = MAX2(minychunk, 0);
484         maxxchunk = MIN2(maxxchunk, this->m_numberOfXChunks);
485         maxychunk = MIN2(maxychunk, this->m_numberOfYChunks);
486
487         bool result = true;
488         for (indexx = minxchunk; indexx < maxxchunk; indexx++) {
489                 for (indexy = minychunk; indexy < maxychunk; indexy++) {
490                         if (!scheduleChunkWhenPossible(graph, indexx, indexy)) {
491                                 result = false;
492                         }
493                 }
494         }
495
496         return result;
497 }
498
499 bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
500 {
501         if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_NOT_SCHEDULED) {
502                 this->m_chunkExecutionStates[chunkNumber] = COM_ES_SCHEDULED;
503                 WorkScheduler::schedule(this, chunkNumber);
504                 return true;
505         }
506         return false;
507 }
508
509 bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk)
510 {
511         if (xChunk < 0 || xChunk >= (int)this->m_numberOfXChunks) {
512                 return true;
513         }
514         if (yChunk < 0 || yChunk >= (int)this->m_numberOfYChunks) {
515                 return true;
516         }
517         int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk;
518         // chunk is already executed
519         if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_EXECUTED) {
520                 return true;
521         }
522
523         // chunk is scheduled, but not executed
524         if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) {
525                 return false;
526         }
527
528         // chunk is nor executed nor scheduled.
529         vector<MemoryProxy *> memoryProxies;
530         this->determineDependingMemoryProxies(&memoryProxies);
531
532         rcti rect;
533         determineChunkRect(&rect, xChunk, yChunk);
534         unsigned int index;
535         bool canBeExecuted = true;
536         rcti area;
537
538         for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
539                 ReadBufferOperation *readOperation = (ReadBufferOperation *)this->m_cachedReadOperations[index];
540                 BLI_rcti_init(&area, 0, 0, 0, 0);
541                 MemoryProxy *memoryProxy = memoryProxies[index];
542                 determineDependingAreaOfInterest(&rect, readOperation, &area);
543                 ExecutionGroup *group = memoryProxy->getExecutor();
544
545                 if (group != NULL) {
546                         if (!group->scheduleAreaWhenPossible(graph, &area)) {
547                                 canBeExecuted = false;
548                         }
549                 }
550                 else {
551                         throw "ERROR";
552                 }
553         }
554
555         if (canBeExecuted) {
556                 scheduleChunk(chunkNumber);
557         }
558
559         return false;
560 }
561
562 void ExecutionGroup::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
563 {
564         this->getOutputNodeOperation()->determineDependingAreaOfInterest(input, readOperation, output);
565 }
566
567 void ExecutionGroup::determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies)
568 {
569         unsigned int index;
570         for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
571                 ReadBufferOperation *readOperation = (ReadBufferOperation *) this->m_cachedReadOperations[index];
572                 memoryProxies->push_back(readOperation->getMemoryProxy());
573         }
574 }
575
576 bool ExecutionGroup::isOpenCL()
577 {
578         return this->m_openCL;
579 }