Fix for a crash when freeing copied scenes.
[blender-staging.git] / source / blender / compositor / operations / COM_DilateErodeOperation.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 "COM_DilateErodeOperation.h"
24 #include "BLI_math.h"
25 #include "COM_OpenCLDevice.h"
26
27 #include "MEM_guardedalloc.h"
28
29 // DilateErode Distance Threshold
30 DilateErodeThresholdOperation::DilateErodeThresholdOperation() : NodeOperation()
31 {
32         this->addInputSocket(COM_DT_VALUE);
33         this->addOutputSocket(COM_DT_VALUE);
34         this->setComplex(true);
35         this->m_inputProgram = NULL;
36         this->m_inset = 0.0f;
37         this->m__switch = 0.5f;
38         this->m_distance = 0.0f;
39 }
40 void DilateErodeThresholdOperation::initExecution()
41 {
42         this->m_inputProgram = this->getInputSocketReader(0);
43         if (this->m_distance < 0.0f) {
44                 this->m_scope = -this->m_distance + this->m_inset;
45         }
46         else {
47                 if (this->m_inset * 2 > this->m_distance) {
48                         this->m_scope = max(this->m_inset * 2 - this->m_distance, this->m_distance);
49                 }
50                 else {
51                         this->m_scope = this->m_distance;
52                 }
53         }
54         if (this->m_scope < 3) {
55                 this->m_scope = 3;
56         }
57 }
58
59 void *DilateErodeThresholdOperation::initializeTileData(rcti *rect)
60 {
61         void *buffer = this->m_inputProgram->initializeTileData(NULL);
62         return buffer;
63 }
64
65 void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, void *data)
66 {
67         float inputValue[4];
68         const float sw = this->m__switch;
69         const float distance = this->m_distance;
70         float pixelvalue;
71         const float rd = this->m_scope * this->m_scope;
72         const float inset = this->m_inset;
73         float mindist = rd * 2;
74
75         MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
76         float *buffer = inputBuffer->getBuffer();
77         rcti *rect = inputBuffer->getRect();
78         const int minx = max(x - this->m_scope, rect->xmin);
79         const int miny = max(y - this->m_scope, rect->ymin);
80         const int maxx = min(x + this->m_scope, rect->xmax);
81         const int maxy = min(y + this->m_scope, rect->ymax);
82         const int bufferWidth = BLI_rcti_size_x(rect);
83         int offset;
84
85         this->m_inputProgram->read(inputValue, x, y, NULL);
86         if (inputValue[0] > sw) {
87                 for (int yi = miny; yi < maxy; yi++) {
88                         const float dy = yi - y;
89                         offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)) * 4;
90                         for (int xi = minx; xi < maxx; xi++) {
91                                 if (buffer[offset] < sw) {
92                                         const float dx = xi - x;
93                                         const float dis = dx * dx + dy * dy;
94                                         mindist = min(mindist, dis);
95                                 }
96                                 offset += 4;
97                         }
98                 }
99                 pixelvalue = -sqrtf(mindist);
100         }
101         else {
102                 for (int yi = miny; yi < maxy; yi++) {
103                         const float dy = yi - y;
104                         offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)) * 4;
105                         for (int xi = minx; xi < maxx; xi++) {
106                                 if (buffer[offset] > sw) {
107                                         const float dx = xi - x;
108                                         const float dis = dx * dx + dy * dy;
109                                         mindist = min(mindist, dis);
110                                 }
111                                 offset += 4;
112
113                         }
114                 }
115                 pixelvalue = sqrtf(mindist);
116         }
117
118         if (distance > 0.0f) {
119                 const float delta = distance - pixelvalue;
120                 if (delta >= 0.0f) {
121                         if (delta >= inset) {
122                                 output[0] = 1.0f;
123                         }
124                         else {
125                                 output[0] = delta / inset;
126                         }
127                 }
128                 else {
129                         output[0] = 0.0f;
130                 }
131         }
132         else {
133                 const float delta = -distance + pixelvalue;
134                 if (delta < 0.0f) {
135                         if (delta < -inset) {
136                                 output[0] = 1.0f;
137                         }
138                         else {
139                                 output[0] = (-delta) / inset;
140                         }
141                 }
142                 else {
143                         output[0] = 0.0f;
144                 }
145         }
146 }
147
148 void DilateErodeThresholdOperation::deinitExecution()
149 {
150         this->m_inputProgram = NULL;
151 }
152
153 bool DilateErodeThresholdOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
154 {
155         rcti newInput;
156
157         newInput.xmax = input->xmax + this->m_scope;
158         newInput.xmin = input->xmin - this->m_scope;
159         newInput.ymax = input->ymax + this->m_scope;
160         newInput.ymin = input->ymin - this->m_scope;
161
162         return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
163 }
164
165 // Dilate Distance
166 DilateDistanceOperation::DilateDistanceOperation() : NodeOperation()
167 {
168         this->addInputSocket(COM_DT_VALUE);
169         this->addOutputSocket(COM_DT_VALUE);
170         this->setComplex(true);
171         this->m_inputProgram = NULL;
172         this->m_distance = 0.0f;
173         this->setOpenCL(true);
174 }
175 void DilateDistanceOperation::initExecution()
176 {
177         this->m_inputProgram = this->getInputSocketReader(0);
178         this->m_scope = this->m_distance;
179         if (this->m_scope < 3) {
180                 this->m_scope = 3;
181         }
182 }
183
184 void *DilateDistanceOperation::initializeTileData(rcti *rect)
185 {
186         void *buffer = this->m_inputProgram->initializeTileData(NULL);
187         return buffer;
188 }
189
190 void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *data)
191 {
192         const float distance = this->m_distance;
193         const float mindist = distance * distance;
194
195         MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
196         float *buffer = inputBuffer->getBuffer();
197         rcti *rect = inputBuffer->getRect();
198         const int minx = max(x - this->m_scope, rect->xmin);
199         const int miny = max(y - this->m_scope, rect->ymin);
200         const int maxx = min(x + this->m_scope, rect->xmax);
201         const int maxy = min(y + this->m_scope, rect->ymax);
202         const int bufferWidth = BLI_rcti_size_x(rect);
203         int offset;
204         
205         float value = 0.0f;
206
207         for (int yi = miny; yi < maxy; yi++) {
208                 const float dy = yi - y;
209                 offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)) * 4;
210                 for (int xi = minx; xi < maxx; xi++) {
211                         const float dx = xi - x;
212                         const float dis = dx * dx + dy * dy;
213                         if (dis <= mindist) {
214                                 value = max(buffer[offset], value);
215                         }
216                         offset += 4;
217                 }
218         }
219         output[0] = value;
220 }
221
222 void DilateDistanceOperation::deinitExecution()
223 {
224         this->m_inputProgram = NULL;
225 }
226
227 bool DilateDistanceOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
228 {
229         rcti newInput;
230
231         newInput.xmax = input->xmax + this->m_scope;
232         newInput.xmin = input->xmin - this->m_scope;
233         newInput.ymax = input->ymax + this->m_scope;
234         newInput.ymin = input->ymin - this->m_scope;
235
236         return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
237 }
238
239 void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device,
240                                             MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
241                                             MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
242                                             list<cl_kernel> *clKernelsToCleanUp)
243 {
244         cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", NULL);
245
246         cl_int distanceSquared = this->m_distance * this->m_distance;
247         cl_int scope = this->m_scope;
248         
249         device->COM_clAttachMemoryBufferToKernelParameter(dilateKernel, 0,  2, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
250         device->COM_clAttachOutputMemoryBufferToKernelParameter(dilateKernel, 1, clOutputBuffer);
251         device->COM_clAttachMemoryBufferOffsetToKernelParameter(dilateKernel, 3, outputMemoryBuffer);
252         clSetKernelArg(dilateKernel, 4, sizeof(cl_int), &scope);
253         clSetKernelArg(dilateKernel, 5, sizeof(cl_int), &distanceSquared);
254         device->COM_clAttachSizeToKernelParameter(dilateKernel, 6, this);
255         device->COM_clEnqueueRange(dilateKernel, outputMemoryBuffer, 7, this);
256 }
257
258 // Erode Distance
259 ErodeDistanceOperation::ErodeDistanceOperation() : DilateDistanceOperation() 
260 {
261         /* pass */
262 }
263
264 void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *data)
265 {
266         const float distance = this->m_distance;
267         const float mindist = distance * distance;
268
269         MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
270         float *buffer = inputBuffer->getBuffer();
271         rcti *rect = inputBuffer->getRect();
272         const int minx = max(x - this->m_scope, rect->xmin);
273         const int miny = max(y - this->m_scope, rect->ymin);
274         const int maxx = min(x + this->m_scope, rect->xmax);
275         const int maxy = min(y + this->m_scope, rect->ymax);
276         const int bufferWidth = BLI_rcti_size_x(rect);
277         int offset;
278         
279         float value = 1.0f;
280
281         for (int yi = miny; yi < maxy; yi++) {
282                 const float dy = yi - y;
283                 offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)) * 4;
284                 for (int xi = minx; xi < maxx; xi++) {
285                         const float dx = xi - x;
286                         const float dis = dx * dx + dy * dy;
287                         if (dis <= mindist) {
288                                 value = min(buffer[offset], value);
289                         }
290                         offset += 4;
291                 }
292         }
293         output[0] = value;
294 }
295
296 void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device,
297                                            MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
298                                            MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
299                                            list<cl_kernel> *clKernelsToCleanUp)
300 {
301         cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", NULL);
302
303         cl_int distanceSquared = this->m_distance * this->m_distance;
304         cl_int scope = this->m_scope;
305         
306         device->COM_clAttachMemoryBufferToKernelParameter(erodeKernel, 0,  2, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
307         device->COM_clAttachOutputMemoryBufferToKernelParameter(erodeKernel, 1, clOutputBuffer);
308         device->COM_clAttachMemoryBufferOffsetToKernelParameter(erodeKernel, 3, outputMemoryBuffer);
309         clSetKernelArg(erodeKernel, 4, sizeof(cl_int), &scope);
310         clSetKernelArg(erodeKernel, 5, sizeof(cl_int), &distanceSquared);
311         device->COM_clAttachSizeToKernelParameter(erodeKernel, 6, this);
312         device->COM_clEnqueueRange(erodeKernel, outputMemoryBuffer, 7, this);
313 }
314
315 // Dilate step
316 DilateStepOperation::DilateStepOperation() : NodeOperation()
317 {
318         this->addInputSocket(COM_DT_VALUE);
319         this->addOutputSocket(COM_DT_VALUE);
320         this->setComplex(true);
321         this->m_inputProgram = NULL;
322 }
323 void DilateStepOperation::initExecution()
324 {
325         this->m_inputProgram = this->getInputSocketReader(0);
326         this->m_cached_buffer = NULL;
327         this->initMutex();
328 }
329
330 void *DilateStepOperation::initializeTileData(rcti *rect)
331 {
332         if (this->m_cached_buffer != NULL) {
333                 return this->m_cached_buffer;
334         }
335         lockMutex();
336         if (this->m_cached_buffer == NULL) {
337                 MemoryBuffer *buffer = (MemoryBuffer *)this->m_inputProgram->initializeTileData(NULL);
338                 float *rectf = buffer->convertToValueBuffer();
339                 int x, y, i;
340                 int bwidth = buffer->getWidth();
341                 int bheight = buffer->getHeight();
342
343                 /*
344                   The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
345                  */
346                 int half_window = this->m_iterations;
347                 int window = half_window * 2 + 1;
348                 float *temp = (float *)MEM_mallocN((2*window - 1) * sizeof(float), "dilate erode temp");
349                 float *buf = (float *)MEM_mallocN((max(bwidth, bheight) + 5*half_window) * sizeof(float), "dilate erode buf");
350
351                 for (y = 0; y < bheight; y++) {
352                         for (x = 0; x < window - 1; x++) {
353                                 buf[x] = -MAXFLOAT;
354                         }
355                         for (x = 0; x < bwidth; x++) {
356                                 buf[x + window - 1] = rectf[bwidth * y + x];
357                         }
358                         for (x = bwidth + window - 1; x < bwidth + 5*half_window; x++) {
359                                 buf[x] = -MAXFLOAT;
360                         }
361
362                         for(i = 0; i < (bwidth + 3*half_window) / window; i++) {
363                                 int start = (i + 1) * window - 1;
364
365                                 temp[window - 1] = buf[start];
366                                 for (x = 1; x < window; x++) {
367                                         temp[window - 1 - x] = max(temp[window - x], buf[start - x]);
368                                         temp[window - 1 + x] = max(temp[window + x - 2], buf[start + x]);
369                                 }
370
371                                 start = half_window + (i-1) * window + 1;
372                                 for (x = -min(0, start); x < window - max(0, start+window - bwidth); x++) {
373                                         rectf[bwidth * y + (start + x)] = max(temp[x], temp[x + window - 1]);
374                                 }
375                         }
376                 }
377
378                 for (x = 0; x < bwidth; x++) {
379                         for (y = 0; y < window - 1; y++) {
380                                 buf[y] = -MAXFLOAT;
381                         }
382                         for (y = 0; y < bheight; y++) {
383                                 buf[y + window - 1] = rectf[bwidth * y + x];
384                         }
385                         for (y = bheight + window - 1; y < bheight + 5*half_window; y++) {
386                                 buf[y] = -MAXFLOAT;
387                         }
388
389                         for(i = 0; i < (bheight + 3*half_window) / window; i++) {
390                                 int start = (i + 1) * window - 1;
391
392                                 temp[window - 1] = buf[start];
393                                 for (y = 1; y < window; y++) {
394                                         temp[window - 1 - y] = max(temp[window - y], buf[start - y]);
395                                         temp[window - 1 + y] = max(temp[window + y - 2], buf[start + y]);
396                                 }
397
398                                 start = half_window + (i-1) * window + 1;
399                                 for (y = -min(0, start); y < window - max(0, start+window - bheight); y++) {
400                                         rectf[bwidth * (y + start) + x] = max(temp[y], temp[y + window - 1]);
401                                 }
402                         }
403                 }
404
405                 MEM_freeN(temp);
406                 MEM_freeN(buf);
407                 this->m_cached_buffer = rectf;
408         }
409         unlockMutex();
410         return this->m_cached_buffer;
411 }
412
413
414 void DilateStepOperation::executePixel(float output[4], int x, int y, void *data)
415 {
416         output[0] = this->m_cached_buffer[y * this->getWidth() + x];
417 }
418
419 void DilateStepOperation::deinitExecution()
420 {
421         this->m_inputProgram = NULL;
422         this->deinitMutex();
423         if (this->m_cached_buffer) {
424                 MEM_freeN(this->m_cached_buffer);
425                 this->m_cached_buffer = NULL;
426         }
427 }
428
429 bool DilateStepOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
430 {
431         if (this->m_cached_buffer) {
432                 return false;
433         }
434         else {
435                 rcti newInput;
436         
437                 newInput.xmax = getWidth();
438                 newInput.xmin = 0;
439                 newInput.ymax = getHeight();
440                 newInput.ymin = 0;
441         
442                 return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
443         }
444 }
445
446 // Erode step
447 ErodeStepOperation::ErodeStepOperation() : DilateStepOperation()
448 {
449         /* pass */
450 }
451
452 void *ErodeStepOperation::initializeTileData(rcti *rect)
453 {
454         if (this->m_cached_buffer != NULL) {
455                 return this->m_cached_buffer;
456         }
457         lockMutex();
458         if (this->m_cached_buffer == NULL) {
459                 MemoryBuffer *buffer = (MemoryBuffer *)this->m_inputProgram->initializeTileData(NULL);
460                 float *rectf = buffer->convertToValueBuffer();
461                 int x, y, i;
462                 int bwidth = buffer->getWidth();
463                 int bheight = buffer->getHeight();
464
465                 int half_window = this->m_iterations;
466                 int window = half_window * 2 + 1;
467                 float *temp = (float *)MEM_mallocN((2*window - 1) * sizeof(float), "dilate erode temp");
468                 float *buf = (float *)MEM_mallocN((max(bwidth, bheight) + 5*half_window) * sizeof(float), "dilate erode buf");
469
470                 for (y = 0; y < bheight; y++) {
471                         for (x = 0; x < window - 1; x++) {
472                                 buf[x] = MAXFLOAT;
473                         }
474                         for (x = 0; x < bwidth; x++) {
475                                 buf[x + window - 1] = rectf[bwidth * y + x];
476                         }
477                         for (x = bwidth + window - 1; x < bwidth + 5*half_window; x++) {
478                                 buf[x] = MAXFLOAT;
479                         }
480
481                         for(i = 0; i < (bwidth + 3*half_window) / window; i++) {
482                                 int start = (i + 1) * window - 1;
483
484                                 temp[window - 1] = buf[start];
485                                 for (x = 1; x < window; x++) {
486                                         temp[window - 1 - x] = min(temp[window - x], buf[start - x]);
487                                         temp[window - 1 + x] = min(temp[window + x - 2], buf[start + x]);
488                                 }
489
490                                 start = half_window + (i-1) * window + 1;
491                                 for (x = -min(0, start); x < window - max(0, start+window - bwidth); x++) {
492                                         rectf[bwidth * y + (start + x)] = min(temp[x], temp[x + window - 1]);
493                                 }
494                         }
495                 }
496
497                 for (x = 0; x < bwidth; x++) {
498                         for (y = 0; y < window - 1; y++) {
499                                 buf[y] = MAXFLOAT;
500                         }
501                         for (y = 0; y < bheight; y++) {
502                                 buf[y + window - 1] = rectf[bwidth * y + x];
503                         }
504                         for (y = bheight + window - 1; y < bheight + 5*half_window; y++) {
505                                 buf[y] = MAXFLOAT;
506                         }
507
508                         for(i = 0; i < (bheight + 3*half_window) / window; i++) {
509                                 int start = (i + 1) * window - 1;
510
511                                 temp[window - 1] = buf[start];
512                                 for (y = 1; y < window; y++) {
513                                         temp[window - 1 - y] = min(temp[window - y], buf[start - y]);
514                                         temp[window - 1 + y] = min(temp[window + y - 2], buf[start + y]);
515                                 }
516
517                                 start = half_window + (i-1) * window + 1;
518                                 for (y = -min(0, start); y < window - max(0, start+window - bheight); y++) {
519                                         rectf[bwidth * (y + start) + x] = min(temp[y], temp[y + window - 1]);
520                                 }
521                         }
522                 }
523
524                 MEM_freeN(temp);
525                 MEM_freeN(buf);
526                 this->m_cached_buffer = rectf;
527         }
528         unlockMutex();
529         return this->m_cached_buffer;
530 }