This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/compositor/intern/COM_ExecutionSystem.cpp
Jeroen Bakker be1b5f82ce * optimized threading
* break out with glare node
 * Added OpenCL kernels compatible with AMD still need some testing.
2012-06-13 12:34:56 +00:00

351 lines
12 KiB
C++

/*
* 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 "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)
{
context.setbNodeTree(editingtree);
bNode* gnode;
for (gnode = (bNode*)editingtree->nodes.first ; gnode ; gnode = (bNode*)gnode->next) {
if (gnode->type == NODE_GROUP && gnode->typeinfo->group_edit_get(gnode)) {
context.setActivegNode(gnode);
break;
}
}
/* 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, NULL);
if (mainOutputNode) {
context.setScene((Scene*)mainOutputNode->getbNode()->id);
this->convertToOperations();
this->groupOperations(); /* group operations in ExecutionGroups */
unsigned int index;
unsigned int resolution[2];
for (index = 0 ; index < this->groups.size(); index ++) {
resolution[0]=0;
resolution[1]=0;
ExecutionGroup *executionGroup = groups[index];
executionGroup->determineResolution(resolution);
}
}
#ifdef COM_DEBUG
ExecutionSystemHelper::debugDump(this);
#endif
}
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 ++;
}
}
unsigned int index;
for (index = 0 ; index < this->operations.size() ; index ++) {
NodeOperation * operation = this->operations[index];
operation->setbNodeTree(this->context.getbNodeTree());
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);
executeGroups(COM_PRIORITY_HIGH);
executeGroups(COM_PRIORITY_MEDIUM);
executeGroups(COM_PRIORITY_LOW);
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();
}
}
void ExecutionSystem::executeGroups(CompositorPriority priority)
{
unsigned int index;
vector<ExecutionGroup*> executionGroups;
this->findOutputExecutionGroup(&executionGroups, priority);
for (index = 0 ; index < executionGroups.size(); index ++) {
ExecutionGroup *group = executionGroups[index];
group->execute(this);
}
}
void ExecutionSystem::addOperation(NodeOperation *operation)
{
ExecutionSystemHelper::addOperation(this->operations, operation);
// operation->setBTree
}
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));
writeoperation->readResolutionFromInputSocket();
}
ReadBufferOperation *readoperation = new ReadBufferOperation();
readoperation->setMemoryProxy(writeoperation->getMemoryProxy());
connection->setFromSocket(readoperation->getOutputSocket());
readoperation->getOutputSocket()->addConnection(connection);
readoperation->readResolutionFromWriteBuffer();
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);
readoperation->readResolutionFromWriteBuffer();
this->addOperation(readoperation);
}
ExecutionSystemHelper::addLink(this->getConnections(), outputsocket, writeOperation->getInputSocket(0));
writeOperation->readResolutionFromInputSocket();
}
}
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()) && !operation->isPreviewOperation()) {
unsigned int resolution[2] = {0,0};
unsigned int preferredResolution[2] = {0,0};
operation->determineResolution(resolution, preferredResolution);
operation->setResolution(resolution);
}
}
for (index = 0 ; index < this->operations.size(); index ++) {
NodeOperation *operation = this->operations[index];
if (operation->isOutputOperation(context.isRendering()) && operation->isPreviewOperation()) {
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, CompositorPriority priority) const
{
unsigned int index;
for (index = 0 ; index < this->groups.size() ; index ++) {
ExecutionGroup *group = this->groups[index];
if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) {
result->push_back(group);
}
}
}
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);
}
}
}