Merge branch 'master' into blender2.8
[blender.git] / source / blender / compositor / intern / COM_NodeOperation.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_NODEOPERATION_H__
24 #define __COM_NODEOPERATION_H__
25
26 #include <list>
27 #include <string>
28 #include <sstream>
29
30 extern "C" {
31 #include "BLI_math_color.h"
32 #include "BLI_math_vector.h"
33 #include "BLI_threads.h"
34 }
35
36 #include "COM_Node.h"
37 #include "COM_MemoryBuffer.h"
38 #include "COM_MemoryProxy.h"
39 #include "COM_SocketReader.h"
40
41 #include "clew.h"
42
43 using std::list;
44 using std::min;
45 using std::max;
46
47 class OpenCLDevice;
48 class ReadBufferOperation;
49 class WriteBufferOperation;
50
51 class NodeOperationInput;
52 class NodeOperationOutput;
53
54 /**
55  * @brief Resize modes of inputsockets
56  * How are the input and working resolutions matched
57  * @ingroup Model
58  */
59 typedef enum InputResizeMode {
60         /** @brief Center the input image to the center of the working area of the node, no resizing occurs */
61         COM_SC_CENTER = NS_CR_CENTER,
62         /** @brief The bottom left of the input image is the bottom left of the working area of the node, no resizing occurs */
63         COM_SC_NO_RESIZE = NS_CR_NONE,
64         /** @brief Fit the width of the input image to the width of the working area of the node */
65         COM_SC_FIT_WIDTH = NS_CR_FIT_WIDTH,
66         /** @brief Fit the height of the input image to the height of the working area of the node */
67         COM_SC_FIT_HEIGHT = NS_CR_FIT_HEIGHT,
68         /** @brief Fit the width or the height of the input image to the width or height of the working area of the node, image will be larger than the working area */
69         COM_SC_FIT = NS_CR_FIT,
70         /** @brief Fit the width and the height of the input image to the width and height of the working area of the node, image will be equally larger than the working area */
71         COM_SC_STRETCH = NS_CR_STRETCH
72 } InputResizeMode;
73
74 /**
75  * @brief NodeOperation contains calculation logic
76  *
77  * Subclasses needs to implement the execution method (defined in SocketReader) to implement logic.
78  * @ingroup Model
79  */
80 class NodeOperation : public SocketReader {
81 public:
82         typedef std::vector<NodeOperationInput*> Inputs;
83         typedef std::vector<NodeOperationOutput*> Outputs;
84
85 private:
86         Inputs m_inputs;
87         Outputs m_outputs;
88
89         /**
90          * @brief the index of the input socket that will be used to determine the resolution
91          */
92         unsigned int m_resolutionInputSocketIndex;
93
94         /**
95          * @brief is this operation a complex one.
96          *
97          * Complex operations are typically doing many reads to calculate the output of a single pixel.
98          * Mostly Filter types (Blurs, Convolution, Defocus etc) need this to be set to true.
99          */
100         bool m_complex;
101
102         /**
103          * @brief can this operation be scheduled on an OpenCL device.
104          * @note Only applicable if complex is True
105          */
106         bool m_openCL;
107
108         /**
109          * @brief mutex reference for very special node initializations
110          * @note only use when you really know what you are doing.
111          * this mutex is used to share data among chunks in the same operation
112          * @see TonemapOperation for an example of usage
113          * @see NodeOperation.initMutex initializes this mutex
114          * @see NodeOperation.deinitMutex deinitializes this mutex
115          * @see NodeOperation.getMutex retrieve a pointer to this mutex.
116          */
117         ThreadMutex m_mutex;
118
119         /**
120          * @brief reference to the editing bNodeTree, used for break and update callback
121          */
122         const bNodeTree *m_btree;
123
124         /**
125          * @brief set to truth when resolution for this operation is set
126          */
127         bool m_isResolutionSet;
128
129 public:
130         virtual ~NodeOperation();
131
132         unsigned int getNumberOfInputSockets() const { return m_inputs.size(); }
133         unsigned int getNumberOfOutputSockets() const { return m_outputs.size(); }
134         NodeOperationOutput *getOutputSocket(unsigned int index) const;
135         NodeOperationOutput *getOutputSocket() const { return getOutputSocket(0); }
136         NodeOperationInput *getInputSocket(unsigned int index) const;
137
138         /** Check if this is an input operation
139          * An input operation is an operation that only has output sockets and no input sockets
140          */
141         bool isInputOperation() const { return m_inputs.empty(); }
142
143         /**
144          * @brief determine the resolution of this node
145          * @note this method will not set the resolution, this is the responsibility of the caller
146          * @param resolution the result of this operation
147          * @param preferredResolution the preferable resolution as no resolution could be determined
148          */
149         virtual void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
150
151         /**
152          * @brief isOutputOperation determines whether this operation is an output of the ExecutionSystem during rendering or editing.
153          *
154          * Default behaviour if not overridden, this operation will not be evaluated as being an output of the ExecutionSystem.
155          *
156          * @see ExecutionSystem
157          * @group check
158          * @param rendering [true false]
159          *  true: rendering
160          *  false: editing
161          *
162          * @return bool the result of this method
163          */
164         virtual bool isOutputOperation(bool /*rendering*/) const { return false; }
165
166         virtual int isSingleThreaded() { return false; }
167
168         void setbNodeTree(const bNodeTree *tree) { this->m_btree = tree; }
169         virtual void initExecution();
170
171         /**
172          * @brief when a chunk is executed by a CPUDevice, this method is called
173          * @ingroup execution
174          * @param rect the rectangle of the chunk (location and size)
175          * @param chunkNumber the chunkNumber to be calculated
176          * @param memoryBuffers all input MemoryBuffer's needed
177          */
178         virtual void executeRegion(rcti * /*rect*/,
179                                    unsigned int /*chunkNumber*/) {}
180
181         /**
182          * @brief when a chunk is executed by an OpenCLDevice, this method is called
183          * @ingroup execution
184          * @note this method is only implemented in WriteBufferOperation
185          * @param context the OpenCL context
186          * @param program the OpenCL program containing all compositor kernels
187          * @param queue the OpenCL command queue of the device the chunk is executed on
188          * @param rect the rectangle of the chunk (location and size)
189          * @param chunkNumber the chunkNumber to be calculated
190          * @param memoryBuffers all input MemoryBuffer's needed
191          * @param outputBuffer the outputbuffer to write to
192          */
193         virtual void executeOpenCLRegion(OpenCLDevice * /*device*/,
194                                          rcti * /*rect*/,
195                                          unsigned int /*chunkNumber*/,
196                                          MemoryBuffer ** /*memoryBuffers*/,
197                                          MemoryBuffer * /*outputBuffer*/) {}
198
199         /**
200          * @brief custom handle to add new tasks to the OpenCL command queue in order to execute a chunk on an GPUDevice
201          * @ingroup execution
202          * @param context the OpenCL context
203          * @param program the OpenCL program containing all compositor kernels
204          * @param queue the OpenCL command queue of the device the chunk is executed on
205          * @param outputMemoryBuffer the allocated memory buffer in main CPU memory
206          * @param clOutputBuffer the allocated memory buffer in OpenCLDevice memory
207          * @param inputMemoryBuffers all input MemoryBuffer's needed
208          * @param clMemToCleanUp all created cl_mem references must be added to this list. Framework will clean this after execution
209          * @param clKernelsToCleanUp all created cl_kernel references must be added to this list. Framework will clean this after execution
210          */
211         virtual void executeOpenCL(OpenCLDevice * /*device*/,
212                                    MemoryBuffer * /*outputMemoryBuffer*/,
213                                    cl_mem /*clOutputBuffer*/,
214                                    MemoryBuffer ** /*inputMemoryBuffers*/,
215                                    list<cl_mem> * /*clMemToCleanUp*/,
216                                    list<cl_kernel> * /*clKernelsToCleanUp*/) {}
217         virtual void deinitExecution();
218
219         bool isResolutionSet() {
220                 return this->m_isResolutionSet;
221         }
222
223         /**
224          * @brief set the resolution
225          * @param resolution the resolution to set
226          */
227         void setResolution(unsigned int resolution[2]) {
228                 if (!isResolutionSet()) {
229                         this->m_width = resolution[0];
230                         this->m_height = resolution[1];
231                         this->m_isResolutionSet = true;
232                 }
233         }
234
235
236         void getConnectedInputSockets(Inputs *sockets);
237
238         /**
239          * @brief is this operation complex
240          *
241          * Complex operations are typically doing many reads to calculate the output of a single pixel.
242          * Mostly Filter types (Blurs, Convolution, Defocus etc) need this to be set to true.
243          */
244         const bool isComplex() const { return this->m_complex; }
245
246         virtual bool isSetOperation() const { return false; }
247
248         /**
249          * @brief is this operation of type ReadBufferOperation
250          * @return [true:false]
251          * @see ReadBufferOperation
252          */
253         virtual const bool isReadBufferOperation() const { return false; }
254
255         /**
256          * @brief is this operation of type WriteBufferOperation
257          * @return [true:false]
258          * @see WriteBufferOperation
259          */
260         virtual const bool isWriteBufferOperation() const { return false; }
261
262         /**
263          * @brief is this operation the active viewer output
264          * user can select an ViewerNode to be active (the result of this node will be drawn on the backdrop)
265          * @return [true:false]
266          * @see BaseViewerOperation
267          */
268         virtual const bool isActiveViewerOutput() const { return false; }
269
270         virtual bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
271
272         /**
273          * @brief set the index of the input socket that will determine the resolution of this operation
274          * @param index the index to set
275          */
276         void setResolutionInputSocketIndex(unsigned int index);
277
278         /**
279          * @brief get the render priority of this node.
280          * @note only applicable for output operations like ViewerOperation
281          * @return CompositorPriority
282          */
283         virtual const CompositorPriority getRenderPriority() const { return COM_PRIORITY_LOW; }
284
285         /**
286          * @brief can this NodeOperation be scheduled on an OpenCLDevice
287          * @see WorkScheduler.schedule
288          * @see ExecutionGroup.addOperation
289          */
290         bool isOpenCL() const { return this->m_openCL; }
291
292         virtual bool isViewerOperation() const { return false; }
293         virtual bool isPreviewOperation() const { return false; }
294         virtual bool isFileOutputOperation() const { return false; }
295         virtual bool isProxyOperation() const { return false; }
296
297         virtual bool useDatatypeConversion() const { return true; }
298
299         inline bool isBreaked() const {
300                 return this->m_btree->test_break(this->m_btree->tbh);
301         }
302
303         inline void updateDraw() {
304                 if (this->m_btree->update_draw)
305                         this->m_btree->update_draw(this->m_btree->udh);
306         }
307 protected:
308         NodeOperation();
309
310         void addInputSocket(DataType datatype, InputResizeMode resize_mode = COM_SC_CENTER);
311         void addOutputSocket(DataType datatype);
312
313         void setWidth(unsigned int width) { this->m_width = width; this->m_isResolutionSet = true; }
314         void setHeight(unsigned int height) { this->m_height = height; this->m_isResolutionSet = true; }
315         SocketReader *getInputSocketReader(unsigned int inputSocketindex);
316         NodeOperation *getInputOperation(unsigned int inputSocketindex);
317
318         void deinitMutex();
319         void initMutex();
320         void lockMutex();
321         void unlockMutex();
322
323         /**
324          * @brief set whether this operation is complex
325          *
326          * Complex operations are typically doing many reads to calculate the output of a single pixel.
327          * Mostly Filter types (Blurs, Convolution, Defocus etc) need this to be set to true.
328          */
329         void setComplex(bool complex) { this->m_complex = complex; }
330
331         /**
332          * @brief set if this NodeOperation can be scheduled on a OpenCLDevice
333          */
334         void setOpenCL(bool openCL) { this->m_openCL = openCL; }
335
336         /* allow the DebugInfo class to look at internals */
337         friend class DebugInfo;
338
339 #ifdef WITH_CXX_GUARDEDALLOC
340         MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
341 #endif
342 };
343
344
345 class NodeOperationInput {
346 private:
347         NodeOperation *m_operation;
348
349         /** Datatype of this socket. Is used for automatically data transformation.
350          * @section data-conversion
351          */
352         DataType m_datatype;
353
354         /** Resize mode of this socket */
355         InputResizeMode m_resizeMode;
356
357         /** Connected output */
358         NodeOperationOutput *m_link;
359
360 public:
361         NodeOperationInput(NodeOperation *op, DataType datatype, InputResizeMode resizeMode = COM_SC_CENTER);
362
363         NodeOperation &getOperation() const { return *m_operation; }
364         DataType getDataType() const { return m_datatype; }
365
366         void setLink(NodeOperationOutput *link) { m_link = link; }
367         NodeOperationOutput *getLink() const { return m_link; }
368         bool isConnected() const { return m_link; }
369
370         void setResizeMode(InputResizeMode resizeMode) { this->m_resizeMode = resizeMode; }
371         InputResizeMode getResizeMode() const { return this->m_resizeMode; }
372
373         SocketReader *getReader();
374
375         void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
376
377 #ifdef WITH_CXX_GUARDEDALLOC
378         MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
379 #endif
380 };
381
382
383 class NodeOperationOutput {
384 private:
385         NodeOperation *m_operation;
386
387         /** Datatype of this socket. Is used for automatically data transformation.
388          * @section data-conversion
389          */
390         DataType m_datatype;
391
392 public:
393         NodeOperationOutput(NodeOperation *op, DataType datatype);
394
395         NodeOperation &getOperation() const { return *m_operation; }
396         DataType getDataType() const { return m_datatype; }
397
398         /**
399          * @brief determine the resolution of this data going through this socket
400          * @param resolution the result of this operation
401          * @param preferredResolution the preferable resolution as no resolution could be determined
402          */
403         void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
404
405 #ifdef WITH_CXX_GUARDEDALLOC
406         MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation")
407 #endif
408 };
409
410 #endif