Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <j.bakker@atmind.nl>2012-05-17 16:49:33 +0400
committerJeroen Bakker <j.bakker@atmind.nl>2012-05-17 16:49:33 +0400
commit044e818cf89ab8587c8acb7927edd740db3a164d (patch)
tree52611bf4cfd0d8cde1d4d80352987737a4cfa559 /source/blender/compositor/intern/COM_ExecutionGroup.cpp
parenteb57856a19127f8867974470dfbfb7524740cd70 (diff)
____
`````|````` | | | ..'''' | | | |______ .'' | | | | ..' | | |_______ |___________ ....'' merge to TRUNK! * The old compositor is still available (Debug Menu: 200) This commit was brought to you by: Developers: * Monique Dewanchand * Jeroen Bakker * Dalai Felinto * Lukas Tönne Review: * Brecht van Lommel Testers: * Nate Wiebe * Wolfgang Faehnle * Carlo Andreacchio * Daniel Salazar * Artur Mag * Christian Krupa * Francesco Siddi * Dan McGrath * Bassam Kurdali But mostly by the community: Gold: Joshua Faulkner Michael Tiemann Francesco Paglia Blender Guru Blender Developers Fund Silver: Pablo Vazquez Joel Heethaar Amrein Olivier Ilias Karasavvidis Thomas Kumlehn Sebastian Koenig Hannu Hoffrén Benjamin Dansie Fred M'ule Michel Vilain Bradley Cathey Gianmichele Mariani Gottfried Hofmann Bjørnar Frøyse Valentijn Bruning Paul Holmes Clemens Rudolph Juris Graphix David Strebel Ronan Zeegers François Tarlier Felipe Andres Esquivel Reed Olaf Beckman Jesus Alberto Olmos Linares Kajimba Maria Figueiredo Alexandr Galperin Francesco Siddi Julio Iglesias Lopez Kjartan Tysdal Thomas Torfs Film Works Teruyuki Nakamura Roger Luethi Benoit Bolsee Stefan Abrahamsen Andreas Mattijat Xavier Bouchoux Blender 3D Graphics and Animation Henk Vostermans Daniel Blanco Delgado BlenderDay/2011 Bradley Cathey Matthieu Dupont de Dinechin Gianmichele Mariani Jérôme Scaillet Bronze (Ivo Grigull, Dylan Urquidi, Philippe Derungs, Phil Beauchamp, Bruce Parrott, Mathieu Quiblier, Daniel Martinez, Leandro Inocencio, Lluc Romaní Brasó, Jonathan Williamson, Michael Ehlen, Karlis Stigis, Dreamsteep, Martin Lindelöf, Filippo Saracino, Douwe van der Veen, Olli Äkräs, Bruno D'Arcangeli, Francisco Sedrez Warmling, Watchmike.ca, peter lener, Matteo Novellino, Martin Kirsch, Austars Schnore, KC Elliott, Massimiliano Puliero, Karl Stein, Wood Design Studios, Omer Khan, Jyrki Kanto, Michał Krupa, Lars Brubaker, Neil Richmond, Adam Kalisz, Robert Garlington, Ian Wilson, Carlo Andreacchio, Jeremias Boos, Robert Holcomb, Gabriel Zöller, Robert Cude, Natibel de Leon, Nathan Turnage, Nicolas Vergnes, Philipp Kleinhenz, Norman Hartig, Louis Kreusel, Christopher Taylor, Giovanni Remondini, Daniel Rentzsch, Nico Partipilo, Thomas Ventresco, Johannes Schwarz, Александр Коротеев, Brendon Harvey, Marcelo G. Malheiros, Marius Giurgi, Richard Burns, Perttu Iso-Metsälä, Steve Bazin, Radoslav Borisov, Yoshiyuki Shida, Julien Guigner, Andrew Hunter, Philipp Oeser, Daniel Thul, Thobias Johansson, Mauro Bonecchi, Georg Piorczynski, Sebastian Michailidis, L M Weedy, Gen X, Stefan Hinze, Nicolò Zubbini, Erik Pusch, Rob Scott, Florian Koch, Charles Razack, Adrian Baker, Oliver Villar Diz, David Revoy, Julio Iglesias Lopez, Coen Spoor, Carlos Folch, Joseph Christie, Victor Hernández García, David Mcsween, James Finnerty, Cory Kruckenberg, Giacomo Graziosi, Olivier Saraja, Lars Brubaker, Eric Hudson, Johannes Schwarz, David Elguea, Marcus Schulderinsky, Karel De Bruijn, Lucas van Wijngaarden, Stefano Ciarrocchi, Mehmet Eribol, Thomas Berglund, Zuofei Song, Dylan Urquidi )
Diffstat (limited to 'source/blender/compositor/intern/COM_ExecutionGroup.cpp')
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cpp566
1 files changed, 566 insertions, 0 deletions
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
new file mode 100644
index 00000000000..22d4366a1a8
--- /dev/null
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
@@ -0,0 +1,566 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Jeroen Bakker
+ * Monique Dewanchand
+ */
+
+#include "COM_ExecutionGroup.h"
+#include "COM_InputSocket.h"
+#include "COM_SocketConnection.h"
+#include "COM_defines.h"
+#include "math.h"
+#include "COM_ExecutionSystem.h"
+#include <sstream>
+#include "COM_ReadBufferOperation.h"
+#include "COM_WriteBufferOperation.h"
+#include "COM_ReadBufferOperation.h"
+#include "COM_WorkScheduler.h"
+#include "COM_ViewerOperation.h"
+#include <stdlib.h>
+#include "BLI_math.h"
+#include "COM_MemoryManager.h"
+#include "PIL_time.h"
+#include "COM_ChunkOrder.h"
+#include <algorithm>
+#include "BLI_math.h"
+#include "COM_ExecutionSystemHelper.h"
+
+ExecutionGroup::ExecutionGroup() {
+ this->isOutput = false;
+ this->complex = false;
+ this->chunkExecutionStates = NULL;
+ this->bTree = NULL;
+ this->height = 0;
+ this->width = 0;
+ this->cachedMaxReadBufferOffset = 0;
+ this->numberOfXChunks = 0;
+ this->numberOfYChunks = 0;
+ this->numberOfChunks = 0;
+ this->initialized = false;
+ this->openCL = false;
+ this->chunksFinished = 0;
+}
+
+int ExecutionGroup::getRenderPriotrity() {
+ return this->getOutputNodeOperation()->getRenderPriority();
+}
+
+bool ExecutionGroup::containsOperation(NodeOperation* operation) {
+ for (vector<NodeOperation*>::const_iterator iterator = this->operations.begin() ; iterator != this->operations.end() ; ++iterator) {
+ NodeOperation* inListOperation = *iterator;
+ if (inListOperation == operation) {
+ return true;
+ }
+ }
+ return false;
+}
+
+const bool ExecutionGroup::isComplex() const {
+ return this->complex;
+}
+
+bool ExecutionGroup::canContainOperation(NodeOperation* operation) {
+ if (!this->initialized) {return true;}
+ if (operation->isReadBufferOperation()) {return true;}
+ if (operation->isWriteBufferOperation()) {return false;}
+ if (operation->isSetOperation()) {return true;}
+
+ if (!this->isComplex()) {
+ return (!operation->isComplex());
+ } else {
+ return false;
+ }
+}
+
+void ExecutionGroup::addOperation(ExecutionSystem *system, NodeOperation *operation) {
+ if (containsOperation(operation)) return;
+ if (canContainOperation(operation)) {
+ if (!operation->isBufferOperation()) {
+ this->complex = operation->isComplex();
+ this->openCL = operation->isOpenCL();
+ this->initialized = true;
+ }
+ this->operations.push_back(operation);
+ if (operation->isReadBufferOperation()) {
+ ReadBufferOperation* readOperation = (ReadBufferOperation*)operation;
+ WriteBufferOperation* writeOperation = readOperation->getMemoryProxy()->getWriteBufferOperation();
+ this->addOperation(system, writeOperation);
+ } else {
+ unsigned int index;
+ for (index = 0 ; index < operation->getNumberOfInputSockets(); index ++) {
+ InputSocket * inputSocket = operation->getInputSocket(index);
+ if (inputSocket->isConnected()) {
+ NodeOperation* node = (NodeOperation*)inputSocket->getConnection()->getFromNode();
+ this->addOperation(system, node);
+ }
+ }
+ }
+ } else {
+ if (operation->isWriteBufferOperation()) {
+ WriteBufferOperation * writeoperation = (WriteBufferOperation*)operation;
+ if (writeoperation->getMemoryProxy()->getExecutor() == NULL) {
+ ExecutionGroup* newGroup = new ExecutionGroup();
+ writeoperation->getMemoryProxy()->setExecutor(newGroup);
+ newGroup->addOperation(system, operation);
+ ExecutionSystemHelper::addExecutionGroup(system->getExecutionGroups(), newGroup);
+ }
+ }
+ }
+}
+
+NodeOperation* ExecutionGroup::getOutputNodeOperation() const{
+ return this->operations[0]; // the first operation of the group is always the output operation.
+}
+
+void ExecutionGroup::initExecution()
+{
+ if (this->chunkExecutionStates != NULL) {
+ delete[] this->chunkExecutionStates;
+ }
+ unsigned int index;
+ determineNumberOfChunks();
+
+ this->chunkExecutionStates = NULL;
+ if (this->numberOfChunks != 0) {
+ this->chunkExecutionStates = new ChunkExecutionState[numberOfChunks];
+ for (index = 0 ; index < numberOfChunks ; index ++) {
+ this->chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED;
+ }
+ }
+
+
+ unsigned int maxNumber = 0;
+
+ for (index = 0 ; index < this->operations.size(); index ++) {
+ NodeOperation* operation = this->operations[index];
+ if (operation->isReadBufferOperation()) {
+ ReadBufferOperation *readOperation = (ReadBufferOperation*)operation;
+ this->cachedReadOperations.push_back(readOperation);
+ maxNumber = max(maxNumber, readOperation->getOffset());
+ }
+ }
+ maxNumber++;
+ this->cachedMaxReadBufferOffset = maxNumber;
+
+}
+
+void ExecutionGroup::deinitExecution() {
+ if (this->chunkExecutionStates != NULL) {
+ delete[] this->chunkExecutionStates;
+ this->chunkExecutionStates = NULL;
+ }
+ this->numberOfChunks = 0;
+ this->numberOfXChunks = 0;
+ this->numberOfYChunks = 0;
+ this->cachedReadOperations.clear();
+ this->bTree = NULL;
+}
+void ExecutionGroup::determineResolution(unsigned int resolution[]) {
+ NodeOperation* operation = this->getOutputNodeOperation();
+ unsigned int preferredResolution[2];
+ preferredResolution[0] = 0;
+ preferredResolution[1] = 0;
+ operation->determineResolution(resolution, preferredResolution);
+ operation->setResolution(resolution);
+ this->setResolution(resolution);
+}
+
+void ExecutionGroup::determineNumberOfChunks() {
+ const float chunkSizef = this->chunkSize;
+ this->numberOfXChunks = ceil(this->width / chunkSizef);
+ this->numberOfYChunks = ceil(this->height / chunkSizef);
+ this->numberOfChunks = this->numberOfXChunks * this->numberOfYChunks;
+}
+
+/**
+ * this method is called for the top execution groups. containing the compositor node or the preview node or the viewer node)
+ */
+void ExecutionGroup::execute(ExecutionSystem* graph) {
+ CompositorContext& context = graph->getContext();
+ const bNodeTree* bTree = context.getbNodeTree();
+ if (this->width == 0 || this->height == 0) {return;} /// @note: break out... no pixels to calculate.
+ if (bTree->test_break && bTree->test_break(bTree->tbh)) {return;} /// @note: early break out for blur and preview nodes
+ if (this->numberOfChunks == 0) {return;} /// @note: early break out
+ unsigned int chunkNumber;
+
+ this->chunksFinished = 0;
+ this->bTree = bTree;
+ unsigned int index;
+ unsigned int *chunkOrder = new unsigned int[this->numberOfChunks];
+
+ for (chunkNumber = 0 ; chunkNumber<this->numberOfChunks ; chunkNumber++) {
+ chunkOrder[chunkNumber] = chunkNumber;
+ }
+ NodeOperation *operation = this->getOutputNodeOperation();
+ float centerX = 0.5;
+ float centerY = 0.5;
+ int chunkorder = COM_TO_CENTER_OUT;
+
+ if (operation->isViewerOperation()) {
+ ViewerBaseOperation* viewer = (ViewerBaseOperation*)operation;
+ centerX = viewer->getCenterX();
+ centerY = viewer->getCenterY();
+ chunkorder = viewer->getChunkOrder();
+ }
+
+ switch (chunkorder) {
+ case COM_TO_RANDOM:
+ for (index = 0 ; index < 2* numberOfChunks ; index ++) {
+ int index1 = rand()%numberOfChunks;
+ int index2 = rand()%numberOfChunks;
+ int s = chunkOrder[index1];
+ chunkOrder[index1] = chunkOrder[index2];
+ chunkOrder[index2] = s;
+ }
+ break;
+ case COM_TO_CENTER_OUT:
+ {
+ ChunkOrderHotspot **hotspots = new ChunkOrderHotspot*[1];
+ hotspots[0] = new ChunkOrderHotspot(this->width*centerX, this->height*centerY, 0.0f);
+ rcti rect;
+ ChunkOrder *chunkOrders = new ChunkOrder[this->numberOfChunks];
+ for (index = 0 ; index < this->numberOfChunks; index ++) {
+ determineChunkRect(&rect, index);
+ chunkOrders[index].setChunkNumber(index);
+ chunkOrders[index].setX(rect.xmin);
+ chunkOrders[index].setY(rect.ymin);
+ chunkOrders[index].determineDistance(hotspots, 1);
+ }
+
+ sort(&chunkOrders[0], &chunkOrders[numberOfChunks-1]);
+ for (index = 0 ; index < numberOfChunks; index ++) {
+ chunkOrder[index] = chunkOrders[index].getChunkNumber();
+ }
+
+ delete hotspots[0];
+ delete[] hotspots;
+ delete[] chunkOrders;
+ }
+ break;
+ case COM_TO_RULE_OF_THIRDS:
+ {
+ ChunkOrderHotspot **hotspots = new ChunkOrderHotspot*[9];
+ unsigned int tx = this->width/6;
+ unsigned int ty = this->height/6;
+ unsigned int mx = this->width/2;
+ unsigned int my = this->height/2;
+ unsigned int bx = mx+2*tx;
+ unsigned int by = my+2*ty;
+
+ float addition = numberOfChunks/COM_RULE_OF_THIRDS_DIVIDER;
+ hotspots[0] = new ChunkOrderHotspot(mx, my, addition*0);
+ hotspots[1] = new ChunkOrderHotspot(tx, my, addition*1);
+ hotspots[2] = new ChunkOrderHotspot(bx, my, addition*2);
+ hotspots[3] = new ChunkOrderHotspot(bx, by, addition*3);
+ hotspots[4] = new ChunkOrderHotspot(tx, ty, addition*4);
+ hotspots[5] = new ChunkOrderHotspot(bx, ty, addition*5);
+ hotspots[6] = new ChunkOrderHotspot(tx, by, addition*6);
+ hotspots[7] = new ChunkOrderHotspot(mx, ty, addition*7);
+ hotspots[8] = new ChunkOrderHotspot(mx, by, addition*8);
+ rcti rect;
+ ChunkOrder *chunkOrders = new ChunkOrder[this->numberOfChunks];
+ for (index = 0 ; index < this->numberOfChunks; index ++) {
+ determineChunkRect(&rect, index);
+ chunkOrders[index].setChunkNumber(index);
+ chunkOrders[index].setX(rect.xmin);
+ chunkOrders[index].setY(rect.ymin);
+ chunkOrders[index].determineDistance(hotspots, 9);
+ }
+
+ sort(&chunkOrders[0], &chunkOrders[numberOfChunks]);
+
+ for (index = 0 ; index < numberOfChunks; index ++) {
+ chunkOrder[index] = chunkOrders[index].getChunkNumber();
+ }
+
+ delete hotspots[0];
+ delete hotspots[1];
+ delete hotspots[2];
+ delete hotspots[3];
+ delete hotspots[4];
+ delete hotspots[5];
+ delete hotspots[6];
+ delete hotspots[7];
+ delete hotspots[8];
+ delete[] hotspots;
+ delete[] chunkOrders;
+ }
+ break;
+ case COM_TO_TOP_DOWN:
+ default:
+ break;
+ }
+
+ bool breaked = false;
+ bool finished = false;
+ unsigned int startIndex = 0;
+ const int maxNumberEvaluated = BLI_system_thread_count()*2;
+
+ while (!finished && !breaked) {
+ unsigned int index;
+ bool startEvaluated = false;
+ finished = true;
+ int numberEvaluated = 0;
+
+ for (index = startIndex ; index < numberOfChunks && numberEvaluated < maxNumberEvaluated; index ++) {
+ int chunkNumber = chunkOrder[index];
+ int yChunk = chunkNumber/this->numberOfXChunks;
+ int xChunk = chunkNumber - (yChunk*this->numberOfXChunks);
+ const ChunkExecutionState state = this->chunkExecutionStates[chunkNumber];
+ if (state == COM_ES_NOT_SCHEDULED) {
+ scheduleChunkWhenPossible(graph, xChunk, yChunk);
+ finished=false;
+ startEvaluated = true;
+ numberEvaluated++;
+ } else if (state == COM_ES_SCHEDULED) {
+ finished=false;
+ startEvaluated = true;
+ numberEvaluated++;
+ } else if (state == COM_ES_EXECUTED && !startEvaluated) {
+ startIndex = index+1;
+ }
+ }
+ PIL_sleep_ms(10);
+
+ if (bTree->test_break && bTree->test_break(bTree->tbh)) {
+ breaked = true;
+ }
+ }
+
+ delete[] chunkOrder;
+}
+
+MemoryBuffer** ExecutionGroup::getInputBuffers(int chunkNumber) {
+ rcti rect;
+ vector<MemoryProxy*> memoryproxies;
+ unsigned int index;
+ determineChunkRect(&rect, chunkNumber);
+
+ this->determineDependingMemoryProxies(&memoryproxies);
+ MemoryBuffer **memoryBuffers = new MemoryBuffer*[this->cachedMaxReadBufferOffset];
+ for (index= 0 ; index < this->cachedMaxReadBufferOffset ; index ++) {
+ memoryBuffers[index] = NULL;
+ }
+ rcti output;
+ for (index = 0 ; index < this->cachedReadOperations.size(); index ++) {
+ ReadBufferOperation *readOperation = (ReadBufferOperation*)this->cachedReadOperations[index];
+ MemoryProxy * memoryProxy = readOperation->getMemoryProxy();
+ this->determineDependingAreaOfInterest(&rect, readOperation, &output);
+ MemoryBuffer* memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer(memoryProxy, &output);
+ memoryBuffers[readOperation->getOffset()] = memoryBuffer;
+ }
+ return memoryBuffers;
+}
+
+MemoryBuffer* ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, rcti *rect) {
+ // find all chunks inside the rect
+ // determine minxchunk, minychunk, maxxchunk, maxychunk where x and y are chunknumbers
+ float chunkSizef = this->chunkSize;
+
+ int indexx, indexy;
+
+ const int minxchunk = floor(rect->xmin/chunkSizef);
+ const int maxxchunk = ceil((rect->xmax-1)/chunkSizef);
+ const int minychunk = floor(rect->ymin/chunkSizef);
+ const int maxychunk = ceil((rect->ymax-1)/chunkSizef);
+
+ if (maxxchunk== minxchunk+1 && maxychunk == minychunk+1) {
+ const int chunkNumber = minxchunk+minychunk*numberOfXChunks;
+ MemoryBuffer *result = MemoryManager::getMemoryBuffer(memoryProxy, chunkNumber);
+ return result;
+ }
+
+ rcti chunkRect;
+ chunkRect.xmin = minxchunk*this->chunkSize;
+ chunkRect.xmax = maxxchunk*this->chunkSize;
+ chunkRect.ymin = minychunk*this->chunkSize;
+ chunkRect.ymax = maxychunk*this->chunkSize;
+
+ CLAMP(chunkRect.xmin, 0, (int)this->width);
+ CLAMP(chunkRect.xmax, 0, (int)this->width);
+ CLAMP(chunkRect.ymin, 0, (int)this->height);
+ CLAMP(chunkRect.ymax, 0, (int)this->height);
+
+ MemoryBuffer *result = new MemoryBuffer(memoryProxy, &chunkRect);
+
+ for (indexx = max(minxchunk, 0); indexx<min((int)this->numberOfXChunks, maxxchunk) ; indexx++) {
+ for (indexy = max(minychunk, 0); indexy<min((int)this->numberOfYChunks, maxychunk) ; indexy++) {
+ int chunkNumber = indexx+indexy*this->numberOfXChunks;
+ MemoryBuffer *chunkBuffer = MemoryManager::getMemoryBuffer(memoryProxy, chunkNumber);
+ result->copyContentFrom(chunkBuffer);
+ }
+ }
+
+ return result;
+}
+
+void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer** memoryBuffers) {
+ if (this->chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED)
+ this->chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
+ else
+ throw "Threading inconsistency";
+
+ this->chunksFinished++;
+ if (memoryBuffers) {
+ for (unsigned int index = 0 ; index < this->cachedMaxReadBufferOffset; index ++) {
+ MemoryBuffer * buffer = memoryBuffers[index];
+ if (buffer) {
+ if (buffer->isTemporarily()) {
+ memoryBuffers[index] = NULL;
+ delete buffer;
+ }
+ }
+ }
+ delete[] memoryBuffers;
+ }
+ if (bTree) {
+ // status report is only performed for top level Execution Groups.
+ float progress = chunksFinished;
+ progress/=numberOfChunks;
+ bTree->progress(bTree->prh, progress);
+ }
+}
+
+inline void ExecutionGroup::determineChunkRect(rcti* rect, const unsigned int xChunk, const unsigned int yChunk ) const {
+ const unsigned int minx = xChunk * chunkSize;
+ const unsigned int miny = yChunk * chunkSize;
+ BLI_init_rcti(rect, minx, min(minx + this->chunkSize, this->width), miny, min(miny + this->chunkSize, this->height));
+}
+
+void ExecutionGroup::determineChunkRect(rcti* rect, const unsigned int chunkNumber) const {
+ const unsigned int yChunk = chunkNumber / numberOfXChunks;
+ const unsigned int xChunk = chunkNumber - (yChunk * numberOfXChunks);
+ determineChunkRect(rect, xChunk, yChunk);
+}
+
+MemoryBuffer* ExecutionGroup::allocateOutputBuffer(int chunkNumber, rcti* rect) {
+ MemoryBuffer* outputBuffer = NULL;
+ // output allocation is only valid when our outputoperation is a memorywriter
+ NodeOperation * operation = this->getOutputNodeOperation();
+ if (operation->isWriteBufferOperation()) {
+ WriteBufferOperation* writeOperation = (WriteBufferOperation*)operation;
+ outputBuffer = MemoryManager::allocateMemoryBuffer(writeOperation->getMemoryProxy(), chunkNumber, rect);
+ }
+ return outputBuffer;
+}
+
+
+bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem * graph, rcti *area) {
+ // find all chunks inside the rect
+ // determine minxchunk, minychunk, maxxchunk, maxychunk where x and y are chunknumbers
+
+ float chunkSizef = this->chunkSize;
+
+ int indexx, indexy;
+ const int minxchunk = floor(area->xmin/chunkSizef);
+ const int maxxchunk = ceil((area->xmax-1)/chunkSizef);
+ const int minychunk = floor(area->ymin/chunkSizef);
+ const int maxychunk = ceil((area->ymax-1)/chunkSizef);
+
+ bool result = true;
+ for (indexx = max(minxchunk, 0); indexx<maxxchunk ; indexx++) {
+ for (indexy = max(minychunk, 0); indexy<maxychunk ; indexy++) {
+ if (!scheduleChunkWhenPossible(graph, indexx, indexy)) {
+ result = false;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) {
+ if (this->chunkExecutionStates[chunkNumber] == COM_ES_NOT_SCHEDULED) {
+ this->chunkExecutionStates[chunkNumber] = COM_ES_SCHEDULED;
+ WorkScheduler::schedule(this, chunkNumber);
+ return true;
+ }
+ return false;
+}
+
+bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem * graph, int xChunk, int yChunk) {
+ if (xChunk < 0 || xChunk >= (int)this->numberOfXChunks) {
+ return true;
+ }
+ if (yChunk < 0 || yChunk >= (int)this->numberOfYChunks) {
+ return true;
+ }
+ int chunkNumber = yChunk*this->numberOfXChunks + xChunk;
+ // chunk is already executed
+ if (this->chunkExecutionStates[chunkNumber] == COM_ES_EXECUTED) {
+ return true;
+ }
+
+ // chunk is scheduled, but not executed
+ if (this->chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) {
+ return false;
+ }
+
+ // chunk is nor executed nor scheduled.
+ vector<MemoryProxy*> memoryProxies;
+ this->determineDependingMemoryProxies(&memoryProxies);
+
+ rcti rect;
+ determineChunkRect(&rect, xChunk, yChunk);
+ unsigned int index;
+ bool canBeExecuted = true;
+ rcti area;
+
+ for (index = 0 ; index < cachedReadOperations.size() ; index ++) {
+ ReadBufferOperation * readOperation = (ReadBufferOperation*)cachedReadOperations[index];
+ BLI_init_rcti(&area, 0, 0, 0, 0);
+ MemoryProxy * memoryProxy = memoryProxies[index];
+ determineDependingAreaOfInterest(&rect, readOperation, &area);
+ ExecutionGroup *group = memoryProxy->getExecutor();
+
+ if (group != NULL) {
+ if (!group->scheduleAreaWhenPossible(graph, &area)) {
+ canBeExecuted = false;
+ }
+ } else {
+ throw "ERROR";
+ }
+ }
+
+ if (canBeExecuted) {
+ scheduleChunk(chunkNumber);
+ }
+
+ return false;
+}
+
+void ExecutionGroup::determineDependingAreaOfInterest(rcti * input, ReadBufferOperation* readOperation, rcti* output) {
+ this->getOutputNodeOperation()->determineDependingAreaOfInterest(input, readOperation, output);
+}
+
+void ExecutionGroup::determineDependingMemoryProxies(vector<MemoryProxy*> *memoryProxies) {
+ unsigned int index;
+ for (index = 0 ; index < this->cachedReadOperations.size() ; index ++) {
+ ReadBufferOperation * readOperation = (ReadBufferOperation*) this->cachedReadOperations[index];
+ memoryProxies->push_back(readOperation->getMemoryProxy());
+ }
+}
+
+bool ExecutionGroup::operator ==(const ExecutionGroup & executionGroup) const {
+ return this->getOutputNodeOperation() == executionGroup.getOutputNodeOperation();
+}
+
+bool ExecutionGroup::isOpenCL() {
+ return this->openCL;
+}