This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/compositor/intern/COM_ExecutionGroup.h
2019-08-02 12:05:13 +10:00

448 lines
12 KiB
C++

/*
* 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.
*
* Copyright 2011, Blender Foundation.
*/
#ifndef __COM_EXECUTIONGROUP_H__
#define __COM_EXECUTIONGROUP_H__
#include "COM_Node.h"
#include "COM_NodeOperation.h"
#include <vector>
#include "BLI_rect.h"
#include "COM_MemoryProxy.h"
#include "COM_Device.h"
#include "COM_CompositorContext.h"
using std::vector;
class ExecutionSystem;
class MemoryProxy;
class ReadBufferOperation;
class Device;
/**
* \brief the execution state of a chunk in an ExecutionGroup
* \ingroup Execution
*/
typedef enum ChunkExecutionState {
/**
* \brief chunk is not yet scheduled
*/
COM_ES_NOT_SCHEDULED = 0,
/**
* \brief chunk is scheduled, but not yet executed
*/
COM_ES_SCHEDULED = 1,
/**
* \brief chunk is executed.
*/
COM_ES_EXECUTED = 2,
} ChunkExecutionState;
/**
* \brief Class ExecutionGroup is a group of Operations that are executed as one.
* This grouping is used to combine Operations that can be executed as one whole when
* multi-processing.
* \ingroup Execution
*/
class ExecutionGroup {
public:
typedef std::vector<NodeOperation *> Operations;
private:
// fields
/**
* \brief list of operations in this ExecutionGroup
*/
Operations m_operations;
/**
* \brief is this ExecutionGroup an input ExecutionGroup
* an input execution group is a group that is at the end of the calculation
* (the output is important for the user).
*/
int m_isOutput;
/**
* \brief Width of the output
*/
unsigned int m_width;
/**
* \brief Height of the output
*/
unsigned int m_height;
/**
* \brief size of a single chunk, being Width or of height
* a chunk is always a square, except at the edges of the MemoryBuffer
*/
unsigned int m_chunkSize;
/**
* \brief number of chunks in the x-axis
*/
unsigned int m_numberOfXChunks;
/**
* \brief number of chunks in the y-axis
*/
unsigned int m_numberOfYChunks;
/**
* \brief total number of chunks
*/
unsigned int m_numberOfChunks;
/**
* \brief contains this ExecutionGroup a complex NodeOperation.
*/
bool m_complex;
/**
* \brief can this ExecutionGroup be scheduled on an OpenCLDevice
*/
bool m_openCL;
/**
* \brief Is this Execution group SingleThreaded
*/
bool m_singleThreaded;
/**
* \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup.
* \note this is used to construct the MemoryBuffers that will be passed during execution.
*/
unsigned int m_cachedMaxReadBufferOffset;
/**
* \brief a cached vector of all read operations in the execution group.
*/
Operations m_cachedReadOperations;
/**
* \brief reference to the original bNodeTree,
* this field is only set for the 'top' execution group.
* \note can only be used to call the callbacks for progress, status and break.
*/
const bNodeTree *m_bTree;
/**
* \brief total number of chunks that have been calculated for this ExecutionGroup
*/
unsigned int m_chunksFinished;
/**
* \brief the chunkExecutionStates holds per chunk the execution state. this state can be
* - COM_ES_NOT_SCHEDULED: not scheduled
* - COM_ES_SCHEDULED: scheduled
* - COM_ES_EXECUTED: executed
*/
ChunkExecutionState *m_chunkExecutionStates;
/**
* \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution
* \note When building the ExecutionGroup Operations are added via recursion.
* First a WriteBufferOperations is added, then the.
* \note Operation containing the settings that is important for the ExecutiongGroup is added,
* \note When this occurs, these settings are copied over from the node to the ExecutionGroup
* \note and the Initialized flag is set to true.
* \see complex
* \see openCL
*/
bool m_initialized;
/**
* \brief denotes boundary for border compositing
* \note measured in pixel space
*/
rcti m_viewerBorder;
/**
* \brief start time of execution
*/
double m_executionStartTime;
// methods
/**
* \brief check whether parameter operation can be added to the execution group
* \param operation: the operation to be added
*/
bool canContainOperation(NodeOperation *operation);
/**
* \brief calculate the actual chunk size of this execution group.
* \note A chunk size is an unsigned int that is both the height and width of a chunk.
* \note The chunk size will not be stored in the chunkSize field. This needs to be done
* \note by the calling method.
*/
unsigned int determineChunkSize();
/**
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk at a position.
* \note Only gives useful results after the determination of the chunksize
* \see determineChunkSize()
*/
void determineChunkRect(rcti *rect, const unsigned int xChunk, const unsigned int yChunk) const;
/**
* \brief determine the number of chunks, based on the chunkSize, width and height.
* \note The result are stored in the fields numberOfChunks, numberOfXChunks, numberOfYChunks
*/
void determineNumberOfChunks();
/**
* \brief try to schedule a specific chunk.
* \note scheduling succeeds when all input requirements are met and the chunks hasn't been
* scheduled yet.
* \param graph:
* \param xChunk:
* \param yChunk:
* \return [true:false]
* true: package(s) are scheduled
* false: scheduling is deferred (depending workpackages are scheduled)
*/
bool scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk);
/**
* \brief try to schedule a specific area.
* \note Check if a certain area is available, when not available this are will be checked.
* \note This method is called from other ExecutionGroup's.
* \param graph:
* \param rect:
* \return [true:false]
* true: package(s) are scheduled
* false: scheduling is deferred (depending workpackages are scheduled)
*/
bool scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *rect);
/**
* \brief add a chunk to the WorkScheduler.
* \param chunknumber:
*/
bool scheduleChunk(unsigned int chunkNumber);
/**
* \brief determine the area of interest of a certain input area
* \note This method only evaluates a single ReadBufferOperation
* \param input: the input area
* \param readOperation: The ReadBufferOperation where the area needs to be evaluated
* \param output: the area needed of the ReadBufferOperation. Result
*/
void determineDependingAreaOfInterest(rcti *input,
ReadBufferOperation *readOperation,
rcti *output);
public:
// constructors
ExecutionGroup();
// methods
/**
* \brief add an operation to this ExecutionGroup
* \note this method will add input of the operations recursively
* \note this method can create multiple ExecutionGroup's
* \param system:
* \param operation:
* \return True if the operation was successfully added
*/
bool addOperation(NodeOperation *operation);
/**
* \brief is this ExecutionGroup an output ExecutionGroup
* \note An OutputExecution group are groups containing a
* \note ViewerOperation, CompositeOperation, PreviewOperation.
* \see NodeOperation.isOutputOperation
*/
int isOutputExecutionGroup() const
{
return this->m_isOutput;
}
/**
* \brief set whether this ExecutionGroup is an output
* \param isOutput:
*/
void setOutputExecutionGroup(int isOutput)
{
this->m_isOutput = isOutput;
}
/**
* \brief determine the resolution of this ExecutionGroup
* \param resolution:
*/
void determineResolution(unsigned int resolution[2]);
/**
* \brief set the resolution of this executiongroup
* \param resolution:
*/
void setResolution(unsigned int resolution[2])
{
this->m_width = resolution[0];
this->m_height = resolution[1];
}
/**
* \brief get the width of this execution group
*/
unsigned int getWidth() const
{
return m_width;
}
/**
* \brief get the height of this execution group
*/
unsigned int getHeight() const
{
return m_height;
}
/**
* \brief does this ExecutionGroup contains a complex NodeOperation
*/
bool isComplex() const
{
return m_complex;
}
/**
* \brief get the output operation of this ExecutionGroup
* \return NodeOperation *output operation
*/
NodeOperation *getOutputOperation() const;
/**
* \brief compose multiple chunks into a single chunk
* \return Memorybuffer *consolidated chunk
*/
MemoryBuffer *constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, rcti *output);
/**
* \brief initExecution is called just before the execution of the whole graph will be done.
* \note The implementation will calculate the chunkSize of this execution group.
*/
void initExecution();
/**
* \brief get all inputbuffers needed to calculate an chunk
* \note all inputbuffers must be executed
* \param chunkNumber: the chunk to be calculated
* \return (MemoryBuffer **) the inputbuffers
*/
MemoryBuffer **getInputBuffersCPU();
/**
* \brief get all inputbuffers needed to calculate an chunk
* \note all inputbuffers must be executed
* \param chunkNumber: the chunk to be calculated
* \return (MemoryBuffer **) the inputbuffers
*/
MemoryBuffer **getInputBuffersOpenCL(int chunkNumber);
/**
* \brief allocate the outputbuffer of a chunk
* \param chunkNumber: the number of the chunk in the ExecutionGroup
* \param rect: the rect of that chunk
* \see determineChunkRect
*/
MemoryBuffer *allocateOutputBuffer(int chunkNumber, rcti *rect);
/**
* \brief after a chunk is executed the needed resources can be freed or unlocked.
* \param chunknumber:
* \param memorybuffers:
*/
void finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers);
/**
* \brief deinitExecution is called just after execution the whole graph.
* \note It will release all needed resources
*/
void deinitExecution();
/**
* \brief schedule an ExecutionGroup
* \note this method will return when all chunks have been calculated, or the execution has
* breaked (by user)
*
* first the order of the chunks will be determined. This is determined by finding the
* ViewerOperation and get the relevant information from it.
* - ChunkOrdering
* - CenterX
* - CenterY
*
* After determining the order of the chunks the chunks will be scheduled
*
* \see ViewerOperation
* \param system:
*/
void execute(ExecutionSystem *system);
/**
* \brief this method determines the MemoryProxy's where this execution group depends on.
* \note After this method determineDependingAreaOfInterest can be called to determine
* \note the area of the MemoryProxy.creator that has to be executed.
* \param memoryProxies: result
*/
void determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies);
/**
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk.
* \note Only gives useful results after the determination of the chunksize
* \see determineChunkSize()
*/
void determineChunkRect(rcti *rect, const unsigned int chunkNumber) const;
/**
* \brief can this ExecutionGroup be scheduled on an OpenCLDevice
* \see WorkScheduler.schedule
*/
bool isOpenCL();
void setChunksize(int chunksize)
{
this->m_chunkSize = chunksize;
}
/**
* \brief get the Render priority of this ExecutionGroup
* \see ExecutionSystem.execute
*/
CompositorPriority getRenderPriotrity();
/**
* \brief set border for viewer operation
* \note all the coordinates are assumed to be in normalized space
*/
void setViewerBorder(float xmin, float xmax, float ymin, float ymax);
void setRenderBorder(float xmin, float xmax, float ymin, float ymax);
/* allow the DebugInfo class to look at internals */
friend class DebugInfo;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:ExecutionGroup")
#endif
};
#endif