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:
Diffstat (limited to 'source/blender/compositor/intern/COM_ExecutionSystem.cpp')
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cpp310
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);
+ }
+ }
+}