diff options
Diffstat (limited to 'source/blender/compositor/intern/COM_ExecutionSystem.cpp')
-rw-r--r-- | source/blender/compositor/intern/COM_ExecutionSystem.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp new file mode 100644 index 00000000000..d82d725d234 --- /dev/null +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -0,0 +1,310 @@ +/* + * 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_ExecutionSystem.h" + +#include "PIL_time.h" +#include "BKE_node.h" +#include "COM_Converter.h" +#include <sstream> +#include "COM_NodeOperation.h" +#include "COM_ExecutionGroup.h" +#include "COM_NodeBase.h" +#include "COM_WorkScheduler.h" +#include "COM_ReadBufferOperation.h" +#include "COM_MemoryManager.h" +#include "stdio.h" +#include "COM_GroupNode.h" +#include "COM_WriteBufferOperation.h" +#include "COM_ReadBufferOperation.h" +#include "COM_ExecutionSystemHelper.h" + +#include "BKE_global.h" + +ExecutionSystem::ExecutionSystem(bNodeTree* editingtree, bool rendering) { + this->context.setbNodeTree(editingtree); + + /* initialize the CompositorContext */ + if (rendering) { + context.setQuality((CompositorQuality)editingtree->render_quality); + } else { + context.setQuality((CompositorQuality)editingtree->edit_quality); + } + context.setRendering(rendering); + context.setHasActiveOpenCLDevices(WorkScheduler::hasGPUDevices() && (editingtree->flag & NTREE_COM_OPENCL)); + + Node* mainOutputNode=NULL; + + mainOutputNode = ExecutionSystemHelper::addbNodeTree(*this, 0, editingtree); + + if (mainOutputNode) { + context.setScene((Scene*)mainOutputNode->getbNode()->id); + this->convertToOperations(); + this->groupOperations(); /* group operations in ExecutionGroups */ + vector<ExecutionGroup*> executionGroups; + this->findOutputExecutionGroup(&executionGroups); + unsigned int index; + unsigned int resolution[2]; + for (index = 0 ; index < executionGroups.size(); index ++) { + resolution[0]=0; + resolution[1]=0; + ExecutionGroup* executionGroup = executionGroups[index]; + executionGroup->determineResolution(resolution); + } + } + + if (G.f & G_DEBUG) ExecutionSystemHelper::debugDump(this); +} + +ExecutionSystem::~ExecutionSystem() { + unsigned int index; + for(index = 0; index < this->connections.size(); index++) { + SocketConnection* connection = this->connections[index]; + delete connection; + } + this->connections.clear(); + for(index = 0; index < this->nodes.size(); index++) { + Node* node = this->nodes[index]; + delete node; + } + this->nodes.clear(); + for(index = 0; index < this->operations.size(); index++) { + NodeOperation* operation = this->operations[index]; + delete operation; + } + this->operations.clear(); + for(index = 0; index < this->groups.size(); index++) { + ExecutionGroup* group = this->groups[index]; + delete group; + } + this->groups.clear(); +} + +void ExecutionSystem::execute() { + unsigned int order = 0; + for( vector<NodeOperation*>::iterator iter = this->operations.begin(); iter != operations.end(); ++iter ) { + NodeBase* node = *iter; + NodeOperation *operation = (NodeOperation*) node; + if (operation->isReadBufferOperation()) { + ReadBufferOperation * readOperation = (ReadBufferOperation*)operation; + readOperation->setOffset(order); + order ++; + } + } + + MemoryManager::initialize(); + unsigned int index; + + for (index = 0 ; index < this->operations.size() ; index ++) { + NodeOperation * operation = this->operations[index]; + operation->initExecution(); + } + for (index = 0 ; index < this->groups.size() ; index ++) { + ExecutionGroup * executionGroup = this->groups[index]; + executionGroup->setChunksize(context.getChunksize()); + executionGroup->initExecution(); + } + + WorkScheduler::start(this->context); + + + vector<ExecutionGroup*> executionGroups; + this->findOutputExecutionGroup(&executionGroups); + + /* start execution of the ExecutionGroups based on priority of their output node */ + for (int priority = 9 ; priority>=0 ; priority--) { + for (index = 0 ; index < executionGroups.size(); index ++) { + ExecutionGroup* group = executionGroups[index]; + NodeOperation* output = group->getOutputNodeOperation(); + if (output->getRenderPriority() == priority) { + group->execute(this); + } + } + } + + WorkScheduler::finish(); + WorkScheduler::stop(); + + for (index = 0 ; index < this->operations.size() ; index ++) { + NodeOperation * operation = this->operations[index]; + operation->deinitExecution(); + } + for (index = 0 ; index < this->groups.size() ; index ++) { + ExecutionGroup * executionGroup = this->groups[index]; + executionGroup->deinitExecution(); + } + MemoryManager::clear(); +} + +void ExecutionSystem::addOperation(NodeOperation *operation) { + ExecutionSystemHelper::addOperation(this->operations, operation); +} + +void ExecutionSystem::addReadWriteBufferOperations(NodeOperation *operation) { + // for every input add write and read operation if input is not a read operation + // only add read operation to other links when they are attached to buffered operations. + unsigned int index; + for (index = 0 ; index < operation->getNumberOfInputSockets();index++) { + InputSocket* inputsocket = operation->getInputSocket(index); + if (inputsocket->isConnected()) { + SocketConnection *connection = inputsocket->getConnection(); + NodeOperation* otherEnd = (NodeOperation*)connection->getFromNode(); + if (!otherEnd->isReadBufferOperation()) { + // check of other end already has write operation + OutputSocket *fromsocket = connection->getFromSocket(); + WriteBufferOperation * writeoperation = fromsocket->findAttachedWriteBufferOperation(); + if (writeoperation == NULL) { + writeoperation = new WriteBufferOperation(); + writeoperation->setbNodeTree(this->getContext().getbNodeTree()); + this->addOperation(writeoperation); + ExecutionSystemHelper::addLink(this->getConnections(), fromsocket, writeoperation->getInputSocket(0)); + } + ReadBufferOperation *readoperation = new ReadBufferOperation(); + readoperation->setMemoryProxy(writeoperation->getMemoryProxy()); + connection->setFromSocket(readoperation->getOutputSocket()); + readoperation->getOutputSocket()->addConnection(connection); + this->addOperation(readoperation); + } + } + } + /* + link the outputsocket to a write operation + link the writeoperation to a read operation + link the read operation to the next node. + */ + OutputSocket * outputsocket = operation->getOutputSocket(); + if (outputsocket->isConnected()) { + int index; + WriteBufferOperation *writeOperation; + writeOperation = new WriteBufferOperation(); + writeOperation->setbNodeTree(this->getContext().getbNodeTree()); + this->addOperation(writeOperation); + for (index = 0 ; index < outputsocket->getNumberOfConnections();index ++) { + SocketConnection * connection = outputsocket->getConnection(index); + ReadBufferOperation* readoperation = new ReadBufferOperation(); + readoperation->setMemoryProxy(writeOperation->getMemoryProxy()); + connection->setFromSocket(readoperation->getOutputSocket()); + readoperation->getOutputSocket()->addConnection(connection); + this->addOperation(readoperation); + } + ExecutionSystemHelper::addLink(this->getConnections(), outputsocket, writeOperation->getInputSocket(0)); + } +} + +void ExecutionSystem::convertToOperations() { + unsigned int index; + // first determine data types of the nodes, this can be used by the node to convert to a different operation system + this->determineActualSocketDataTypes((vector<NodeBase*>&)this->nodes); + for(index = 0; index < this->nodes.size(); index++) { + Node* node = (Node*)this->nodes[index]; + node->convertToOperations(this, &this->context); + } + + // update the socket types of the operations. this will be used to add conversion operations in the system + this->determineActualSocketDataTypes((vector<NodeBase*>&)this->operations); + for (index = 0 ; index < this->connections.size(); index ++) { + SocketConnection *connection = this->connections[index]; + if (connection->isValid()) { + if (connection->getFromSocket()->getActualDataType() != connection->getToSocket()->getActualDataType()) { + Converter::convertDataType(connection, this); + } + } + } + + // determine all resolutions of the operations (Width/Height) + for (index = 0 ; index < this->operations.size(); index ++) { + NodeOperation* operation= this->operations[index]; + if (operation->isOutputOperation(context.isRendering())) { + unsigned int resolution[2] = {0,0}; + unsigned int preferredResolution[2] = {0,0}; + operation->determineResolution(resolution, preferredResolution); + operation->setResolution(resolution); + } + } + + // add convert resolution operations when needed. + for (index = 0 ; index < this->connections.size(); index ++) { + SocketConnection *connection = this->connections[index]; + if (connection->isValid()) { + if (connection->needsResolutionConversion()) { + Converter::convertResolution(connection, this); + } + } + } + +} + +void ExecutionSystem::groupOperations() { + vector<NodeOperation*> outputOperations; + NodeOperation * operation; + unsigned int index; + // surround complex operations with ReadBufferOperation and WriteBufferOperation + for(index = 0; index < this->operations.size(); index++) { + operation = this->operations[index]; + if (operation->isComplex()) { + this->addReadWriteBufferOperations(operation); + } + } + ExecutionSystemHelper::findOutputNodeOperations(&outputOperations, this->getOperations(), this->context.isRendering()); + for( vector<NodeOperation*>::iterator iter = outputOperations.begin(); iter != outputOperations.end(); ++iter ) { + operation = *iter; + ExecutionGroup *group = new ExecutionGroup(); + group->addOperation(this, operation); + group->setOutputExecutionGroup(true); + ExecutionSystemHelper::addExecutionGroup(this->getExecutionGroups(), group); + } +} + +void ExecutionSystem::addSocketConnection(SocketConnection *connection) +{ + this->connections.push_back(connection); +} + + +void ExecutionSystem::determineActualSocketDataTypes(vector<NodeBase*> &nodes) { + unsigned int index; + /* first do all input nodes */ + for(index = 0; index < nodes.size(); index++) { + NodeBase* node = nodes[index]; + if (node->isInputNode()) { + node->determineActualSocketDataTypes(); + } + } + + /* then all other nodes */ + for(index = 0; index < nodes.size(); index++) { + NodeBase* node = nodes[index]; + if (!node->isInputNode()) { + node->determineActualSocketDataTypes(); + } + } +} + +void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup*> *result) const { + unsigned int index; + for (index = 0 ; index < this->groups.size() ; index ++) { + ExecutionGroup* group = this->groups[index]; + if (group->isOutputExecutionGroup()) { + result->push_back(group); + } + } +} |