svn merge ^/trunk/blender -r48078:48105
[blender.git] / source / blender / compositor / intern / COM_NodeOperation.cpp
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 #include <typeinfo>
24 #include <stdio.h>
25
26 #include "COM_NodeOperation.h"
27 #include "COM_InputSocket.h"
28 #include "COM_SocketConnection.h"
29 #include "COM_defines.h"
30
31 NodeOperation::NodeOperation()
32 {
33         this->resolutionInputSocketIndex = 0;
34         this->complex = false;
35         this->width = 0;
36         this->height = 0;
37         this->openCL = false;
38         this->btree = NULL;
39 }
40
41 void NodeOperation::determineResolution(unsigned int resolution[], unsigned int preferredResolution[])
42 {
43         unsigned int temp[2];
44         unsigned int temp2[2];
45         vector<InputSocket *> &inputsockets = this->getInputSockets();
46         
47         for (unsigned int index = 0; index < inputsockets.size(); index++) {
48                 InputSocket *inputSocket = inputsockets[index];
49                 if (inputSocket->isConnected()) {
50                         if (index == this->resolutionInputSocketIndex) {
51                                 inputSocket->determineResolution(resolution, preferredResolution);
52                                 temp2[0] = resolution[0];
53                                 temp2[1] = resolution[1];
54                                 break;
55                         }
56                 }
57         }
58         for (unsigned int index = 0; index < inputsockets.size(); index++) {
59                 InputSocket *inputSocket = inputsockets[index];
60                 if (inputSocket->isConnected()) {
61                         if (index != resolutionInputSocketIndex) {
62                                 inputSocket->determineResolution(temp, temp2);
63                         }
64                 }
65         }
66 }
67 void NodeOperation::setResolutionInputSocketIndex(unsigned int index)
68 {
69         this->resolutionInputSocketIndex = index;
70 }
71 void NodeOperation::initExecution()
72 {
73         /* pass */
74 }
75
76 void NodeOperation::initMutex()
77 {
78         BLI_mutex_init(&mutex);
79 }
80
81 void NodeOperation::lockMutex()
82 {
83         BLI_mutex_lock(&mutex);
84 }
85
86 void NodeOperation::unlockMutex()
87 {
88         BLI_mutex_unlock(&mutex);
89 }
90
91 void NodeOperation::deinitMutex()
92 {
93         BLI_mutex_end(&mutex);
94 }
95
96 void NodeOperation::deinitExecution()
97 {
98         /* pass */
99 }
100 SocketReader *NodeOperation::getInputSocketReader(unsigned int inputSocketIndex)
101 {
102         return this->getInputSocket(inputSocketIndex)->getReader();
103 }
104 NodeOperation *NodeOperation::getInputOperation(unsigned int inputSocketIndex)
105 {
106         return this->getInputSocket(inputSocketIndex)->getOperation();
107 }
108
109 void NodeOperation::getConnectedInputSockets(vector<InputSocket *> *sockets)
110 {
111         vector<InputSocket *> &inputsockets = this->getInputSockets();
112         for (vector<InputSocket *>::iterator iterator = inputsockets.begin(); iterator != inputsockets.end(); iterator++) {
113                 InputSocket *socket = *iterator;
114                 if (socket->isConnected()) {
115                         sockets->push_back(socket);
116                 }
117         }
118 }
119
120 bool NodeOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
121 {
122         if (this->isInputNode()) {
123                 BLI_init_rcti(output, input->xmin, input->xmax, input->ymin, input->ymax);
124                 return false;
125         }
126         else {
127                 unsigned int index;
128                 vector<InputSocket *> &inputsockets = this->getInputSockets();
129         
130                 for (index = 0; index < inputsockets.size(); index++) {
131                         InputSocket *inputsocket = inputsockets[index];
132                         if (inputsocket->isConnected()) {
133                                 NodeOperation *inputoperation = (NodeOperation *)inputsocket->getConnection()->getFromNode();
134                                 bool result = inputoperation->determineDependingAreaOfInterest(input, readOperation, output);
135                                 if (result) {
136                                         return true;
137                                 }
138                         }
139                 }
140                 return false;
141         }
142 }
143
144 cl_mem NodeOperation::COM_clAttachMemoryBufferToKernelParameter(cl_context context, cl_kernel kernel, int parameterIndex, int offsetIndex, list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader)
145 {
146         cl_int error;
147         MemoryBuffer *result = (MemoryBuffer *)reader->initializeTileData(NULL, inputMemoryBuffers);
148
149         const cl_image_format imageFormat = {
150                 CL_RGBA,
151                 CL_FLOAT
152         };
153
154         cl_mem clBuffer = clCreateImage2D(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, &imageFormat, result->getWidth(),
155                                           result->getHeight(), 0, result->getBuffer(), &error);
156         
157         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
158         if (error == CL_SUCCESS) cleanup->push_back(clBuffer);
159
160         error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clBuffer);
161         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
162         
163         COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, offsetIndex, result);
164         return clBuffer;
165 }
166         
167 void NodeOperation::COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel, int offsetIndex, MemoryBuffer *memoryBuffer) 
168 {
169         if (offsetIndex != -1) {
170                 cl_int error;
171                 rcti *rect = memoryBuffer->getRect();
172                 cl_int2 offset = {rect->xmin, rect->ymin};
173
174                 error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
175                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
176         }
177 }
178
179 void NodeOperation::COM_clAttachSizeToKernelParameter(cl_kernel kernel, int offsetIndex) 
180 {
181         if (offsetIndex != -1) {
182                 cl_int error;
183                 cl_int2 offset = {this->getWidth(), this->getHeight()};
184
185                 error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
186                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
187         }
188 }
189
190 void NodeOperation::COM_clAttachOutputMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, cl_mem clOutputMemoryBuffer) 
191 {
192         cl_int error;
193         error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clOutputMemoryBuffer);
194         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
195 }
196
197 void NodeOperation::COM_clEnqueueRange(cl_command_queue queue, cl_kernel kernel, MemoryBuffer *outputMemoryBuffer) {
198         cl_int error;
199         const size_t size[] = {outputMemoryBuffer->getWidth(), outputMemoryBuffer->getHeight()};
200         
201         error = clEnqueueNDRangeKernel(queue, kernel, 2, NULL, size, 0, 0, 0, NULL);
202         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
203 }
204
205 void NodeOperation::COM_clEnqueueRange(cl_command_queue queue, cl_kernel kernel, MemoryBuffer *outputMemoryBuffer, int offsetIndex) {
206         cl_int error;
207         const int width = outputMemoryBuffer->getWidth();
208         const int height = outputMemoryBuffer->getHeight();
209         int offsetx;
210         int offsety;
211         const int localSize = 128;
212         size_t size[2];
213         cl_int2 offset;
214         
215         bool breaked = false;
216         for (offsety = 0; offsety < height && (!breaked); offsety += localSize) {
217                 offset[1] = offsety;
218                 if (offsety + localSize < height) {
219                         size[1] = localSize;
220                 }
221                 else {
222                         size[1] = height - offsety;
223                 }
224                 for (offsetx = 0; offsetx < width && (!breaked); offsetx += localSize) {
225                         if (offsetx + localSize < width) {
226                                 size[0] = localSize;
227                         }
228                         else {
229                                 size[0] = width - offsetx;
230                         }
231                         offset[0] = offsetx;
232
233                         error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
234                         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
235                         error = clEnqueueNDRangeKernel(queue, kernel, 2, NULL, size, 0, 0, 0, NULL);
236                         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
237                         clFlush(queue);
238                         if (isBreaked()) {
239                                 breaked = false;
240                         }
241                 }
242         }
243 }
244
245 cl_kernel NodeOperation::COM_clCreateKernel(cl_program program, const char *kernelname, list<cl_kernel> *clKernelsToCleanUp) 
246 {
247         cl_int error;
248         cl_kernel kernel = clCreateKernel(program, kernelname, &error);
249         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
250         else {
251                 if (clKernelsToCleanUp) clKernelsToCleanUp->push_back(kernel);
252         }
253         return kernel;
254         
255 }