svn merge ^/trunk/blender -r49520:49531
[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
35 /**
36  * @brief the execution state of a chunk in an ExecutionGroup
37  * @ingroup Execution
38  */
39 typedef enum ChunkExecutionState {
40         /**
41          * @brief chunk is not yet scheduled
42          */
43         COM_ES_NOT_SCHEDULED = 0,
44         /**
45          * @brief chunk is scheduled, but not yet executed
46          */
47         COM_ES_SCHEDULED = 1,
48         /**
49          * @brief chunk is executed.
50          */
51         COM_ES_EXECUTED = 2
52 } ChunkExecutionState;
53
54 class MemoryProxy;
55 class ReadBufferOperation;
56 class Device;
57
58 /**
59  * @brief Class ExecutionGroup is a group of NodeOperations that are executed as one.
60  * This grouping is used to combine Operations that can be executed as one whole when multi-processing.
61  * @ingroup Execution
62  */
63 class ExecutionGroup {
64 private:
65         // fields
66         
67         /**
68          * @brief list of operations in this ExecutionGroup
69          */
70         vector<NodeOperation *> m_operations;
71         
72         /**
73          * @brief is this ExecutionGroup an input ExecutionGroup
74          * an input execution group is a group that is at the end of the calculation (the output is important for the user)
75          */
76         int m_isOutput;
77         
78         /**
79          * @brief Width of the output
80          */
81         unsigned int m_width;
82         
83         /**
84          * @brief Height of the output
85          */
86         unsigned int m_height;
87         
88         /**
89          * @brief size of a single chunk, being Width or of height
90          * a chunk is always a square, except at the edges of the MemoryBuffer
91          */
92         unsigned int m_chunkSize;
93         
94         /**
95          * @brief number of chunks in the x-axis
96          */
97         unsigned int m_numberOfXChunks;
98         
99         /**
100          * @brief number of chunks in the y-axis
101          */
102         unsigned int m_numberOfYChunks;
103         
104         /**
105          * @brief total number of chunks
106          */
107         unsigned int m_numberOfChunks;
108         
109         /**
110          * @brief contains this ExecutionGroup a complex NodeOperation.
111          */
112         bool m_complex;
113         
114         /**
115          * @brief can this ExecutionGroup be scheduled on an OpenCLDevice
116          */
117         bool m_openCL;
118         
119         /**
120          * @brief Is this Execution group SingleThreaded
121          */
122         bool m_singleThreaded;
123         
124         /**
125          * @brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup.
126          * @note this is used to construct the MemoryBuffers that will be passed during execution.
127          */
128         unsigned int m_cachedMaxReadBufferOffset;
129         
130         /**
131          * @brief a cached vector of all read operations in the execution group.
132          */
133         vector<NodeOperation *> m_cachedReadOperations;
134         
135         /**
136          * @brief reference to the original bNodeTree, this field is only set for the 'top' execution group.
137          * @note can only be used to call the callbacks for progress, status and break
138          */
139         const bNodeTree *m_bTree;
140         
141         /**
142          * @brief total number of chunks that have been calculated for this ExecutionGroup
143          */
144         unsigned int m_chunksFinished;
145         
146         /**
147          * @brief the chunkExecutionStates holds per chunk the execution state. this state can be
148          *   - COM_ES_NOT_SCHEDULED: not scheduled
149          *   - COM_ES_SCHEDULED: scheduled
150          *   - COM_ES_EXECUTED: executed
151          */
152         ChunkExecutionState *m_chunkExecutionStates;
153         
154         /**
155          * @brief indicator when this ExecutionGroup has valid NodeOperations in its vector for Execution
156          * @note When building the ExecutionGroup NodeOperations are added via recursion. First a WriteBufferOperations is added, then the
157          * @note Operation containing the settings that is important for the ExecutiongGroup is added,
158          * @note When this occurs, these settings are copied over from the node to the ExecutionGroup
159          * @note and the Initialized flag is set to true.
160          * @see complex
161          * @see openCL
162          */
163         bool m_initialized;
164         
165         // methods
166         /**
167          * @brief check whether parameter operation can be added to the execution group
168          * @param operation the operation to be added
169          */
170         bool canContainOperation(NodeOperation *operation);
171                 
172         /**
173          * @brief calculate the actual chunk size of this execution group.
174          * @note A chunk size is an unsigned int that is both the height and width of a chunk.
175          * @note The chunk size will not be stored in the chunkSize field. This needs to be done
176          * @note by the calling method.
177          */
178         unsigned int determineChunkSize();
179         
180         
181         /**
182          * @brief Determine the rect (minx, maxx, miny, maxy) of a chunk at a position.
183          * @note Only gives useful results ater the determination of the chunksize
184          * @see determineChunkSize()
185          */
186         void determineChunkRect(rcti *rect, const unsigned int xChunk, const unsigned int yChunk) const;
187         
188         /**
189          * @brief determine the number of chunks, based on the chunkSize, width and height.
190          * @note The result are stored in the fields numberOfChunks, numberOfXChunks, numberOfYChunks
191          */
192         void determineNumberOfChunks();
193         
194         /**
195          * @brief try to schedule a specific chunk.
196          * @note scheduling succeeds when all input requirements are met and the chunks hasen't been scheduled yet.
197          * @param graph
198          * @param xChunk
199          * @param yChunk
200          * @return [true:false]
201          * true: package(s) are scheduled
202          * false: scheduling is deferred (depending workpackages are scheduled)
203          */
204         bool scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk);
205
206         /**
207          * @brief try to schedule a specific area.
208          * @note Check if a certain area is available, when not available this are will be checked.
209          * @note This method is called from other ExecutionGroup's.
210          * @param graph
211          * @param rect
212          * @return [true:false]
213          * true: package(s) are scheduled
214          * false: scheduling is deferred (depending workpackages are scheduled)
215          */
216         bool scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *rect);
217
218         /**
219          * @brief add a chunk to the WorkScheduler.
220          * @param chunknumber
221          */
222         bool scheduleChunk(unsigned int chunkNumber);
223         
224         /**
225          * @brief determine the area of interest of a certain input area
226          * @note This method only evaluates a single ReadBufferOperation
227          * @param input the input area
228          * @param readOperation The ReadBufferOperation where the area needs to be evaluated
229          * @param output the area needed of the ReadBufferOperation. Result
230          */
231         void determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
232
233
234 public:
235         // constructors
236         ExecutionGroup();
237                 
238         // methods
239         /**
240          * @brief check to see if a NodeOperation is already inside this execution group
241          * @param operation the NodeOperation to check
242          * @return [true,false]
243          */
244         bool containsOperation(NodeOperation *operation);
245         
246         /**
247          * @brief add an operation to this ExecutionGroup
248          * @note this method will add input of the operations recursivly
249          * @note this method can create multiple ExecutionGroup's
250          * @param system
251          * @param operation
252          */
253         void addOperation(ExecutionSystem *system, NodeOperation *operation);
254         
255         /**
256          * @brief is this ExecutionGroup an output ExecutionGroup
257          * @note An OutputExecution group are groups containing a
258          * @note ViewerOperation, CompositeOperation, PreviewOperation.
259          * @see NodeOperation.isOutputOperation
260          */
261         const int isOutputExecutionGroup() const { return this->m_isOutput; }
262
263         /**
264          * @brief set whether this ExecutionGroup is an output
265          * @param isOutput
266          */
267         void setOutputExecutionGroup(int isOutput) { this->m_isOutput = isOutput; }
268
269         /**
270          * @brief determine the resolution of this ExecutionGroup
271          * @param resolution
272          */
273         void determineResolution(unsigned int resolution[]);
274         
275         /**
276          * @brief set the resolution of this executiongroup
277          * @param resolution
278          */
279         void setResolution(unsigned int resolution[]) { this->m_width = resolution[0]; this->m_height = resolution[1]; }
280         
281         /**
282          * @brief get the width of this execution group
283          */
284         const unsigned int getWidth() { return this->m_width; }
285         
286         /**
287          * @brief get the height of this execution group
288          */
289         const unsigned int getHeight() { return this->m_height; }
290         
291         /**
292          * @brief does this ExecutionGroup contains a complex NodeOperation
293          */
294         const bool isComplex() const;
295         
296         
297         /**
298          * @brief get the output operation of this ExecutionGroup
299          * @return NodeOperation *output operation
300          */
301         NodeOperation *getOutputNodeOperation() const;
302         
303         /**
304          * @brief compose multiple chunks into a single chunk
305          * @return Memorybuffer *consolidated chunk
306          */
307         MemoryBuffer *constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, rcti *output);
308         
309         /**
310          * @brief initExecution is called just before the execution of the whole graph will be done.
311          * @note The implementation will calculate the chunkSize of this execution group.
312          */
313         void initExecution();
314         
315         /**
316          * @brief get all inputbuffers needed to calculate an chunk
317          * @note all inputbuffers must be executed
318          * @param chunkNumber the chunk to be calculated
319          * @return (MemoryBuffer **) the inputbuffers
320          */
321         MemoryBuffer **getInputBuffersCPU();
322
323         /**
324          * @brief get all inputbuffers needed to calculate an chunk
325          * @note all inputbuffers must be executed
326          * @param chunkNumber the chunk to be calculated
327          * @return (MemoryBuffer **) the inputbuffers
328          */
329         MemoryBuffer **getInputBuffersOpenCL(int chunkNumber);
330
331         /**
332          * @brief allocate the outputbuffer of a chunk
333          * @param chunkNumber the number of the chunk in the ExecutionGroup
334          * @param rect the rect of that chunk
335          * @see determineChunkRect
336          */
337         MemoryBuffer *allocateOutputBuffer(int chunkNumber, rcti *rect);
338         
339         /**
340          * @brief after a chunk is executed the needed resources can be freed or unlocked.
341          * @param chunknumber
342          * @param memorybuffers
343          */
344         void finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers);
345         
346         /**
347          * @brief deinitExecution is called just after execution the whole graph.
348          * @note It will release all needed resources
349          */
350         void deinitExecution();
351         
352         
353         /**
354          * @brief schedule an ExecutionGroup
355          * @note this method will return when all chunks have been calculated, or the execution has breaked (by user)
356          *
357          * first the order of the chunks will be determined. This is determined by finding the ViewerOperation and get the relevant information from it.
358          *   - ChunkOrdering
359          *   - CenterX
360          *   - CenterY
361          *
362          * After determining the order of the chunks the chunks will be scheduled
363          *
364          * @see ViewerOperation
365          * @param system
366          */
367         void execute(ExecutionSystem *system);
368         
369         /**
370          * @brief this method determines the MemoryProxy's where this execution group depends on.
371          * @note After this method determineDependingAreaOfInterest can be called to determine
372          * @note the area of the MemoryProxy.creator thas has to be executed.
373          * @param memoryProxies result
374          */
375         void determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies);
376         
377         /**
378          * @brief Determine the rect (minx, maxx, miny, maxy) of a chunk.
379          * @note Only gives useful results ater the determination of the chunksize
380          * @see determineChunkSize()
381          */
382         void determineChunkRect(rcti *rect, const unsigned int chunkNumber) const;
383
384         /**
385          * @brief can this ExecutionGroup be scheduled on an OpenCLDevice
386          * @see WorkScheduler.schedule
387          */
388         bool isOpenCL();
389
390         void setChunksize(int chunksize) { this->m_chunkSize = chunksize; }
391
392         /**
393          * @brief get the Render priority of this ExecutionGroup
394          * @see ExecutionSystem.execute
395          */
396         CompositorPriority getRenderPriotrity();
397
398 #ifdef WITH_CXX_GUARDEDALLOC
399         MEM_CXX_CLASS_ALLOC_FUNCS("COM:ExecutionGroup")
400 #endif
401 };
402
403 #endif