8f170aab2fb4c81d82e6dcbce85c8e9f85fd7036
[blender.git] / source / blender / compositor / intern / COM_ExecutionGroup.h
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor:
19  *      Jeroen Bakker
20  *      Monique Dewanchand
21  */
22
23 #ifndef __COM_EXECUTIONGROUP_H__
24 #define __COM_EXECUTIONGROUP_H__
25
26 #include "COM_Node.h"
27 #include "COM_NodeOperation.h"
28 #include <vector>
29 #include "BLI_rect.h"
30 #include "COM_MemoryProxy.h"
31 #include "COM_Device.h"
32 #include "COM_CompositorContext.h"
33
34 using std::vector;
35
36 class ExecutionSystem;
37 class MemoryProxy;
38 class ReadBufferOperation;
39 class Device;
40
41 /**
42  * \brief the execution state of a chunk in an ExecutionGroup
43  * \ingroup Execution
44  */
45 typedef enum ChunkExecutionState {
46         /**
47          * \brief chunk is not yet scheduled
48          */
49         COM_ES_NOT_SCHEDULED = 0,
50         /**
51          * \brief chunk is scheduled, but not yet executed
52          */
53         COM_ES_SCHEDULED = 1,
54         /**
55          * \brief chunk is executed.
56          */
57         COM_ES_EXECUTED = 2
58 } ChunkExecutionState;
59
60 /**
61  * \brief Class ExecutionGroup is a group of Operations that are executed as one.
62  * This grouping is used to combine Operations that can be executed as one whole when multi-processing.
63  * \ingroup Execution
64  */
65 class ExecutionGroup {
66 public:
67         typedef std::vector<NodeOperation*> Operations;
68
69 private:
70         // fields
71
72         /**
73          * \brief list of operations in this ExecutionGroup
74          */
75         Operations m_operations;
76
77         /**
78          * \brief is this ExecutionGroup an input ExecutionGroup
79          * an input execution group is a group that is at the end of the calculation (the output is important for the user)
80          */
81         int m_isOutput;
82
83         /**
84          * \brief Width of the output
85          */
86         unsigned int m_width;
87
88         /**
89          * \brief Height of the output
90          */
91         unsigned int m_height;
92
93         /**
94          * \brief size of a single chunk, being Width or of height
95          * a chunk is always a square, except at the edges of the MemoryBuffer
96          */
97         unsigned int m_chunkSize;
98
99         /**
100          * \brief number of chunks in the x-axis
101          */
102         unsigned int m_numberOfXChunks;
103
104         /**
105          * \brief number of chunks in the y-axis
106          */
107         unsigned int m_numberOfYChunks;
108
109         /**
110          * \brief total number of chunks
111          */
112         unsigned int m_numberOfChunks;
113
114         /**
115          * \brief contains this ExecutionGroup a complex NodeOperation.
116          */
117         bool m_complex;
118
119         /**
120          * \brief can this ExecutionGroup be scheduled on an OpenCLDevice
121          */
122         bool m_openCL;
123
124         /**
125          * \brief Is this Execution group SingleThreaded
126          */
127         bool m_singleThreaded;
128
129         /**
130          * \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup.
131          * \note this is used to construct the MemoryBuffers that will be passed during execution.
132          */
133         unsigned int m_cachedMaxReadBufferOffset;
134
135         /**
136          * \brief a cached vector of all read operations in the execution group.
137          */
138         Operations m_cachedReadOperations;
139
140         /**
141          * \brief reference to the original bNodeTree, this field is only set for the 'top' execution group.
142          * \note can only be used to call the callbacks for progress, status and break
143          */
144         const bNodeTree *m_bTree;
145
146         /**
147          * \brief total number of chunks that have been calculated for this ExecutionGroup
148          */
149         unsigned int m_chunksFinished;
150
151         /**
152          * \brief the chunkExecutionStates holds per chunk the execution state. this state can be
153          *   - COM_ES_NOT_SCHEDULED: not scheduled
154          *   - COM_ES_SCHEDULED: scheduled
155          *   - COM_ES_EXECUTED: executed
156          */
157         ChunkExecutionState *m_chunkExecutionStates;
158
159         /**
160          * \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution
161          * \note When building the ExecutionGroup Operations are added via recursion. First a WriteBufferOperations is added, then the
162          * \note Operation containing the settings that is important for the ExecutiongGroup is added,
163          * \note When this occurs, these settings are copied over from the node to the ExecutionGroup
164          * \note and the Initialized flag is set to true.
165          * \see complex
166          * \see openCL
167          */
168         bool m_initialized;
169
170         /**
171          * \brief denotes boundary for border compositing
172          * \note measured in pixel space
173          */
174         rcti m_viewerBorder;
175
176         /**
177          * \brief start time of execution
178          */
179         double m_executionStartTime;
180
181         // methods
182         /**
183          * \brief check whether parameter operation can be added to the execution group
184          * \param operation: the operation to be added
185          */
186         bool canContainOperation(NodeOperation *operation);
187
188         /**
189          * \brief calculate the actual chunk size of this execution group.
190          * \note A chunk size is an unsigned int that is both the height and width of a chunk.
191          * \note The chunk size will not be stored in the chunkSize field. This needs to be done
192          * \note by the calling method.
193          */
194         unsigned int determineChunkSize();
195
196
197         /**
198          * \brief Determine the rect (minx, maxx, miny, maxy) of a chunk at a position.
199          * \note Only gives useful results ater the determination of the chunksize
200          * \see determineChunkSize()
201          */
202         void determineChunkRect(rcti *rect, const unsigned int xChunk, const unsigned int yChunk) const;
203
204         /**
205          * \brief determine the number of chunks, based on the chunkSize, width and height.
206          * \note The result are stored in the fields numberOfChunks, numberOfXChunks, numberOfYChunks
207          */
208         void determineNumberOfChunks();
209
210         /**
211          * \brief try to schedule a specific chunk.
212          * \note scheduling succeeds when all input requirements are met and the chunks hasn't been scheduled yet.
213          * \param graph:
214          * \param xChunk:
215          * \param yChunk:
216          * \return [true:false]
217          * true: package(s) are scheduled
218          * false: scheduling is deferred (depending workpackages are scheduled)
219          */
220         bool scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk);
221
222         /**
223          * \brief try to schedule a specific area.
224          * \note Check if a certain area is available, when not available this are will be checked.
225          * \note This method is called from other ExecutionGroup's.
226          * \param graph:
227          * \param rect:
228          * \return [true:false]
229          * true: package(s) are scheduled
230          * false: scheduling is deferred (depending workpackages are scheduled)
231          */
232         bool scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *rect);
233
234         /**
235          * \brief add a chunk to the WorkScheduler.
236          * \param chunknumber:
237          */
238         bool scheduleChunk(unsigned int chunkNumber);
239
240         /**
241          * \brief determine the area of interest of a certain input area
242          * \note This method only evaluates a single ReadBufferOperation
243          * \param input: the input area
244          * \param readOperation: The ReadBufferOperation where the area needs to be evaluated
245          * \param output: the area needed of the ReadBufferOperation. Result
246          */
247         void determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
248
249
250 public:
251         // constructors
252         ExecutionGroup();
253
254         // methods
255         /**
256          * \brief add an operation to this ExecutionGroup
257          * \note this method will add input of the operations recursively
258          * \note this method can create multiple ExecutionGroup's
259          * \param system:
260          * \param operation:
261          * \return True if the operation was successfully added
262          */
263         bool addOperation(NodeOperation *operation);
264
265         /**
266          * \brief is this ExecutionGroup an output ExecutionGroup
267          * \note An OutputExecution group are groups containing a
268          * \note ViewerOperation, CompositeOperation, PreviewOperation.
269          * \see NodeOperation.isOutputOperation
270          */
271         int isOutputExecutionGroup() const { return this->m_isOutput; }
272
273         /**
274          * \brief set whether this ExecutionGroup is an output
275          * \param isOutput:
276          */
277         void setOutputExecutionGroup(int isOutput) { this->m_isOutput = isOutput; }
278
279         /**
280          * \brief determine the resolution of this ExecutionGroup
281          * \param resolution:
282          */
283         void determineResolution(unsigned int resolution[2]);
284
285         /**
286          * \brief set the resolution of this executiongroup
287          * \param resolution:
288          */
289         void setResolution(unsigned int resolution[2]) { this->m_width = resolution[0]; this->m_height = resolution[1]; }
290
291         /**
292          * \brief get the width of this execution group
293          */
294         unsigned int getWidth() const { return m_width; }
295
296         /**
297          * \brief get the height of this execution group
298          */
299         unsigned int getHeight() const { return m_height; }
300
301         /**
302          * \brief does this ExecutionGroup contains a complex NodeOperation
303          */
304         bool isComplex() const { return m_complex; }
305
306
307         /**
308          * \brief get the output operation of this ExecutionGroup
309          * \return NodeOperation *output operation
310          */
311         NodeOperation *getOutputOperation() const;
312
313         /**
314          * \brief compose multiple chunks into a single chunk
315          * \return Memorybuffer *consolidated chunk
316          */
317         MemoryBuffer *constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, rcti *output);
318
319         /**
320          * \brief initExecution is called just before the execution of the whole graph will be done.
321          * \note The implementation will calculate the chunkSize of this execution group.
322          */
323         void initExecution();
324
325         /**
326          * \brief get all inputbuffers needed to calculate an chunk
327          * \note all inputbuffers must be executed
328          * \param chunkNumber: the chunk to be calculated
329          * \return (MemoryBuffer **) the inputbuffers
330          */
331         MemoryBuffer **getInputBuffersCPU();
332
333         /**
334          * \brief get all inputbuffers needed to calculate an chunk
335          * \note all inputbuffers must be executed
336          * \param chunkNumber: the chunk to be calculated
337          * \return (MemoryBuffer **) the inputbuffers
338          */
339         MemoryBuffer **getInputBuffersOpenCL(int chunkNumber);
340
341         /**
342          * \brief allocate the outputbuffer of a chunk
343          * \param chunkNumber: the number of the chunk in the ExecutionGroup
344          * \param rect: the rect of that chunk
345          * \see determineChunkRect
346          */
347         MemoryBuffer *allocateOutputBuffer(int chunkNumber, rcti *rect);
348
349         /**
350          * \brief after a chunk is executed the needed resources can be freed or unlocked.
351          * \param chunknumber:
352          * \param memorybuffers:
353          */
354         void finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers);
355
356         /**
357          * \brief deinitExecution is called just after execution the whole graph.
358          * \note It will release all needed resources
359          */
360         void deinitExecution();
361
362
363         /**
364          * \brief schedule an ExecutionGroup
365          * \note this method will return when all chunks have been calculated, or the execution has breaked (by user)
366          *
367          * first the order of the chunks will be determined. This is determined by finding the ViewerOperation and get the relevant information from it.
368          *   - ChunkOrdering
369          *   - CenterX
370          *   - CenterY
371          *
372          * After determining the order of the chunks the chunks will be scheduled
373          *
374          * \see ViewerOperation
375          * \param system:
376          */
377         void execute(ExecutionSystem *system);
378
379         /**
380          * \brief this method determines the MemoryProxy's where this execution group depends on.
381          * \note After this method determineDependingAreaOfInterest can be called to determine
382          * \note the area of the MemoryProxy.creator that has to be executed.
383          * \param memoryProxies: result
384          */
385         void determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies);
386
387         /**
388          * \brief Determine the rect (minx, maxx, miny, maxy) of a chunk.
389          * \note Only gives useful results ater the determination of the chunksize
390          * \see determineChunkSize()
391          */
392         void determineChunkRect(rcti *rect, const unsigned int chunkNumber) const;
393
394         /**
395          * \brief can this ExecutionGroup be scheduled on an OpenCLDevice
396          * \see WorkScheduler.schedule
397          */
398         bool isOpenCL();
399
400         void setChunksize(int chunksize) { this->m_chunkSize = chunksize; }
401
402         /**
403          * \brief get the Render priority of this ExecutionGroup
404          * \see ExecutionSystem.execute
405          */
406         CompositorPriority getRenderPriotrity();
407
408         /**
409          * \brief set border for viewer operation
410          * \note all the coordinates are assumed to be in normalized space
411          */
412         void setViewerBorder(float xmin, float xmax, float ymin, float ymax);
413
414         void setRenderBorder(float xmin, float xmax, float ymin, float ymax);
415
416         /* allow the DebugInfo class to look at internals */
417         friend class DebugInfo;
418
419 #ifdef WITH_CXX_GUARDEDALLOC
420         MEM_CXX_CLASS_ALLOC_FUNCS("COM:ExecutionGroup")
421 #endif
422 };
423
424 #endif