~ubuntu-branches/ubuntu/trusty/blender/trusty

« back to all changes in this revision

Viewing changes to source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-03-06 12:08:47 UTC
  • mfrom: (1.5.1) (14.1.8 experimental)
  • Revision ID: package-import@ubuntu.com-20130306120847-frjfaryb2zrotwcg
Tags: 2.66a-1ubuntu1
* Resynchronize with Debian (LP: #1076930, #1089256, #1052743, #999024,
  #1122888, #1147084)
* debian/control:
  - Lower build-depends on libavcodec-dev since we're not
    doing the libav9 transition in Ubuntu yet

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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_VariableSizeBokehBlurOperation.h"
 
24
#include "BLI_math.h"
 
25
#include "COM_OpenCLDevice.h"
 
26
 
 
27
extern "C" {
 
28
        #include "RE_pipeline.h"
 
29
}
 
30
 
 
31
VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation() : NodeOperation()
 
32
{
 
33
        this->addInputSocket(COM_DT_COLOR);
 
34
        this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); // do not resize the bokeh image.
 
35
        this->addInputSocket(COM_DT_VALUE); // radius
 
36
#ifdef COM_DEFOCUS_SEARCH
 
37
        this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); // inverse search radius optimization structure.
 
38
#endif
 
39
        this->addOutputSocket(COM_DT_COLOR);
 
40
        this->setComplex(true);
 
41
        this->setOpenCL(true);
 
42
 
 
43
        this->m_inputProgram = NULL;
 
44
        this->m_inputBokehProgram = NULL;
 
45
        this->m_inputSizeProgram = NULL;
 
46
        this->m_maxBlur = 32.0f;
 
47
        this->m_threshold = 1.0f;
 
48
        this->m_do_size_scale = false;
 
49
#ifdef COM_DEFOCUS_SEARCH
 
50
        this->m_inputSearchProgram = NULL;
 
51
#endif
 
52
}
 
53
 
 
54
 
 
55
void VariableSizeBokehBlurOperation::initExecution()
 
56
{
 
57
        this->m_inputProgram = getInputSocketReader(0);
 
58
        this->m_inputBokehProgram = getInputSocketReader(1);
 
59
        this->m_inputSizeProgram = getInputSocketReader(2);
 
60
#ifdef COM_DEFOCUS_SEARCH
 
61
        this->m_inputSearchProgram = getInputSocketReader(3);
 
62
#endif
 
63
        QualityStepHelper::initExecution(COM_QH_INCREASE);
 
64
}
 
65
struct VariableSizeBokehBlurTileData
 
66
{
 
67
        MemoryBuffer *color;
 
68
        MemoryBuffer *bokeh;
 
69
        MemoryBuffer *size;
 
70
        int maxBlurScalar;
 
71
};
 
72
 
 
73
void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect)
 
74
{
 
75
        VariableSizeBokehBlurTileData *data = new VariableSizeBokehBlurTileData();
 
76
        data->color = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect);
 
77
        data->bokeh = (MemoryBuffer *)this->m_inputBokehProgram->initializeTileData(rect);
 
78
        data->size = (MemoryBuffer *)this->m_inputSizeProgram->initializeTileData(rect);
 
79
 
 
80
 
 
81
        rcti rect2;
 
82
        this->determineDependingAreaOfInterest(rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2);
 
83
 
 
84
        const float max_dim = max(m_width, m_height);
 
85
        const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
 
86
 
 
87
        data->maxBlurScalar = (int)(data->size->getMaximumValue(&rect2) * scalar);
 
88
        CLAMP(data->maxBlurScalar, 1.0f, this->m_maxBlur);
 
89
        return data;
 
90
}
 
91
 
 
92
void VariableSizeBokehBlurOperation::deinitializeTileData(rcti *rect, void *data)
 
93
{
 
94
        VariableSizeBokehBlurTileData *result = (VariableSizeBokehBlurTileData *)data;
 
95
        delete result;
 
96
}
 
97
 
 
98
void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
 
99
{
 
100
        VariableSizeBokehBlurTileData *tileData = (VariableSizeBokehBlurTileData *)data;
 
101
        MemoryBuffer *inputProgramBuffer = tileData->color;
 
102
        MemoryBuffer *inputBokehBuffer = tileData->bokeh;
 
103
        MemoryBuffer *inputSizeBuffer = tileData->size;
 
104
        float *inputSizeFloatBuffer = inputSizeBuffer->getBuffer();
 
105
        float *inputProgramFloatBuffer = inputProgramBuffer->getBuffer();
 
106
        float readColor[4];
 
107
        float bokeh[4];
 
108
        float tempSize[4];
 
109
        float multiplier_accum[4];
 
110
        float color_accum[4];
 
111
 
 
112
        const float max_dim = max(m_width, m_height);
 
113
        const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
 
114
        int maxBlurScalar = tileData->maxBlurScalar;
 
115
 
 
116
        BLI_assert(inputBokehBuffer->getWidth()  == COM_BLUR_BOKEH_PIXELS);
 
117
        BLI_assert(inputBokehBuffer->getHeight() == COM_BLUR_BOKEH_PIXELS);
 
118
 
 
119
#ifdef COM_DEFOCUS_SEARCH
 
120
        float search[4];
 
121
        this->m_inputSearchProgram->read(search, x / InverseSearchRadiusOperation::DIVIDER, y / InverseSearchRadiusOperation::DIVIDER, NULL);
 
122
        int minx = search[0];
 
123
        int miny = search[1];
 
124
        int maxx = search[2];
 
125
        int maxy = search[3];
 
126
#else
 
127
        int minx = max(x - maxBlurScalar, 0);
 
128
        int miny = max(y - maxBlurScalar, 0);
 
129
        int maxx = min(x + maxBlurScalar, (int)m_width);
 
130
        int maxy = min(y + maxBlurScalar, (int)m_height);
 
131
#endif
 
132
        {
 
133
                inputSizeBuffer->readNoCheck(tempSize, x, y);
 
134
                inputProgramBuffer->readNoCheck(readColor, x, y);
 
135
 
 
136
                copy_v4_v4(color_accum, readColor);
 
137
                copy_v4_fl(multiplier_accum, 1.0f);
 
138
                float size_center = tempSize[0] * scalar;
 
139
                
 
140
                const int addXStep = QualityStepHelper::getStep() * COM_NUMBER_OF_CHANNELS;
 
141
                
 
142
                if (size_center > this->m_threshold) {
 
143
                        for (int ny = miny; ny < maxy; ny += QualityStepHelper::getStep()) {
 
144
                                float dy = ny - y;
 
145
                                int offsetNy = ny * inputSizeBuffer->getWidth() * COM_NUMBER_OF_CHANNELS;
 
146
                                int offsetNxNy = offsetNy + (minx * COM_NUMBER_OF_CHANNELS);
 
147
                                for (int nx = minx; nx < maxx; nx += QualityStepHelper::getStep()) {
 
148
                                        if (nx != x || ny != y) {
 
149
                                                float size = inputSizeFloatBuffer[offsetNxNy] * scalar;
 
150
                                                if (size > this->m_threshold) {
 
151
                                                        float dx = nx - x;
 
152
                                                        if (size > fabsf(dx) && size > fabsf(dy)) {
 
153
                                                                float uv[2] = {
 
154
                                                                    (float)(COM_BLUR_BOKEH_PIXELS / 2) + (dx / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1),
 
155
                                                                    (float)(COM_BLUR_BOKEH_PIXELS / 2) + (dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1)};
 
156
                                                                inputBokehBuffer->readNoCheck(bokeh, uv[0], uv[1]);
 
157
                                                                madd_v4_v4v4(color_accum, bokeh, &inputProgramFloatBuffer[offsetNxNy]);
 
158
                                                                add_v4_v4(multiplier_accum, bokeh);
 
159
                                                        }
 
160
                                                }
 
161
                                        }
 
162
                                        offsetNxNy += addXStep;
 
163
                                }
 
164
                        }
 
165
                }
 
166
 
 
167
                output[0] = color_accum[0] / multiplier_accum[0];
 
168
                output[1] = color_accum[1] / multiplier_accum[1];
 
169
                output[2] = color_accum[2] / multiplier_accum[2];
 
170
                output[3] = color_accum[3] / multiplier_accum[3];
 
171
 
 
172
                /* blend in out values over the threshold, otherwise we get sharp, ugly transitions */
 
173
                if ((size_center > this->m_threshold) &&
 
174
                    (size_center < this->m_threshold * 2.0f))
 
175
                {
 
176
                        /* factor from 0-1 */
 
177
                        float fac = (size_center - this->m_threshold) / this->m_threshold;
 
178
                        interp_v4_v4v4(output, readColor, output, fac);
 
179
                }
 
180
        }
 
181
 
 
182
}
 
183
 
 
184
void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
 
185
                                       MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, 
 
186
                                       MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp, 
 
187
                                       list<cl_kernel> *clKernelsToCleanUp) 
 
188
{
 
189
        cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", NULL);
 
190
 
 
191
        cl_int step = this->getStep();
 
192
        cl_int maxBlur;
 
193
        cl_float threshold = this->m_threshold;
 
194
        
 
195
        MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer(inputMemoryBuffers);
 
196
 
 
197
        const float max_dim = max(m_width, m_height);
 
198
        cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
 
199
 
 
200
        maxBlur = (cl_int)sizeMemoryBuffer->getMaximumValue() * scalar;
 
201
        maxBlur = min(maxBlur, this->m_maxBlur);
 
202
 
 
203
        device->COM_clAttachMemoryBufferToKernelParameter(defocusKernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
 
204
        device->COM_clAttachMemoryBufferToKernelParameter(defocusKernel, 1,  -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram);
 
205
        device->COM_clAttachMemoryBufferToKernelParameter(defocusKernel, 2,  4, clMemToCleanUp, inputMemoryBuffers, this->m_inputSizeProgram);
 
206
        device->COM_clAttachOutputMemoryBufferToKernelParameter(defocusKernel, 3, clOutputBuffer);
 
207
        device->COM_clAttachMemoryBufferOffsetToKernelParameter(defocusKernel, 5, outputMemoryBuffer);
 
208
        clSetKernelArg(defocusKernel, 6, sizeof(cl_int), &step);
 
209
        clSetKernelArg(defocusKernel, 7, sizeof(cl_int), &maxBlur);
 
210
        clSetKernelArg(defocusKernel, 8, sizeof(cl_float), &threshold);
 
211
        clSetKernelArg(defocusKernel, 9, sizeof(cl_float), &scalar);
 
212
        device->COM_clAttachSizeToKernelParameter(defocusKernel, 10, this);
 
213
        
 
214
        device->COM_clEnqueueRange(defocusKernel, outputMemoryBuffer, 11, this);
 
215
}
 
216
 
 
217
void VariableSizeBokehBlurOperation::deinitExecution()
 
218
{
 
219
        this->m_inputProgram = NULL;
 
220
        this->m_inputBokehProgram = NULL;
 
221
        this->m_inputSizeProgram = NULL;
 
222
#ifdef COM_DEFOCUS_SEARCH
 
223
        this->m_inputSearchProgram = NULL;
 
224
#endif
 
225
}
 
226
 
 
227
bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
 
228
{
 
229
        rcti newInput;
 
230
        rcti bokehInput;
 
231
 
 
232
        const float max_dim = max(m_width, m_height);
 
233
        const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
 
234
        int maxBlurScalar = this->m_maxBlur * scalar;
 
235
 
 
236
        newInput.xmax = input->xmax + maxBlurScalar + 2;
 
237
        newInput.xmin = input->xmin - maxBlurScalar + 2;
 
238
        newInput.ymax = input->ymax + maxBlurScalar - 2;
 
239
        newInput.ymin = input->ymin - maxBlurScalar - 2;
 
240
        bokehInput.xmax = COM_BLUR_BOKEH_PIXELS;
 
241
        bokehInput.xmin = 0;
 
242
        bokehInput.ymax = COM_BLUR_BOKEH_PIXELS;
 
243
        bokehInput.ymin = 0;
 
244
        
 
245
 
 
246
        NodeOperation *operation = getInputOperation(2);
 
247
        if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output) ) {
 
248
                return true;
 
249
        }
 
250
        operation = getInputOperation(1);
 
251
        if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output) ) {
 
252
                return true;
 
253
        }
 
254
#ifdef COM_DEFOCUS_SEARCH
 
255
        rcti searchInput;
 
256
        searchInput.xmax = (input->xmax / InverseSearchRadiusOperation::DIVIDER) + 1;
 
257
        searchInput.xmin = (input->xmin / InverseSearchRadiusOperation::DIVIDER) - 1;
 
258
        searchInput.ymax = (input->ymax / InverseSearchRadiusOperation::DIVIDER) + 1;
 
259
        searchInput.ymin = (input->ymin / InverseSearchRadiusOperation::DIVIDER) - 1;
 
260
        operation = getInputOperation(3);
 
261
        if (operation->determineDependingAreaOfInterest(&searchInput, readOperation, output) ) {
 
262
                return true;
 
263
        }
 
264
#endif
 
265
        operation = getInputOperation(0);
 
266
        if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output) ) {
 
267
                return true;
 
268
        }
 
269
        return false;
 
270
}
 
271
 
 
272
#ifdef COM_DEFOCUS_SEARCH
 
273
// InverseSearchRadiusOperation
 
274
InverseSearchRadiusOperation::InverseSearchRadiusOperation() : NodeOperation() 
 
275
{
 
276
        this->addInputSocket(COM_DT_VALUE, COM_SC_NO_RESIZE); // radius
 
277
        this->addOutputSocket(COM_DT_COLOR);
 
278
        this->setComplex(true);
 
279
        this->m_inputRadius = NULL;
 
280
}
 
281
 
 
282
void InverseSearchRadiusOperation::initExecution() 
 
283
{
 
284
        this->m_inputRadius = this->getInputSocketReader(0);
 
285
}
 
286
 
 
287
voi *InverseSearchRadiusOperation::initializeTileData(rcti *rect)
 
288
{
 
289
        MemoryBuffer * data = new MemoryBuffer(NULL, rect);
 
290
        float *buffer = data->getBuffer();
 
291
        int x, y;
 
292
        int width = this->m_inputRadius->getWidth();
 
293
        int height = this->m_inputRadius->getHeight();
 
294
        float temp[4];
 
295
        int offset = 0;
 
296
        for (y = rect->ymin; y < rect->ymax ; y++) {
 
297
                for (x = rect->xmin; x < rect->xmax ; x++) {
 
298
                        int rx = x * DIVIDER;
 
299
                        int ry = y * DIVIDER;
 
300
                        buffer[offset] = MAX2(rx - m_maxBlur, 0);
 
301
                        buffer[offset + 1] = MAX2(ry - m_maxBlur, 0);
 
302
                        buffer[offset + 2] = MIN2(rx + DIVIDER + m_maxBlur, width);
 
303
                        buffer[offset + 3] = MIN2(ry + DIVIDER + m_maxBlur, height);
 
304
                        offset += 4;
 
305
                }
 
306
        }
 
307
//      for (x = rect->xmin; x < rect->xmax ; x++) {
 
308
//              for (y = rect->ymin; y < rect->ymax ; y++) {
 
309
//                      int rx = x * DIVIDER;
 
310
//                      int ry = y * DIVIDER;
 
311
//                      float radius = 0.0f;
 
312
//                      float maxx = x;
 
313
//                      float maxy = y;
 
314
        
 
315
//                      for (int x2 = 0 ; x2 < DIVIDER ; x2 ++) {
 
316
//                              for (int y2 = 0 ; y2 < DIVIDER ; y2 ++) {
 
317
//                                      this->m_inputRadius->read(temp, rx+x2, ry+y2, COM_PS_NEAREST);
 
318
//                                      if (radius < temp[0]) {
 
319
//                                              radius = temp[0];
 
320
//                                              maxx = x2;
 
321
//                                              maxy = y2;
 
322
//                                      }
 
323
//                              }
 
324
//                      }
 
325
//                      int impactRadius = ceil(radius / DIVIDER);
 
326
//                      for (int x2 = x - impactRadius ; x2 < x + impactRadius ; x2 ++) {
 
327
//                              for (int y2 = y - impactRadius ; y2 < y + impactRadius ; y2 ++) {
 
328
//                                      data->read(temp, x2, y2);
 
329
//                                      temp[0] = MIN2(temp[0], maxx);
 
330
//                                      temp[1] = MIN2(temp[1], maxy);
 
331
//                                      temp[2] = MAX2(temp[2], maxx);
 
332
//                                      temp[3] = MAX2(temp[3], maxy);
 
333
//                                      data->writePixel(x2, y2, temp);
 
334
//                              }
 
335
//                      }
 
336
//              }
 
337
//      }
 
338
        return data;
 
339
}
 
340
 
 
341
void InverseSearchRadiusOperation::executePixel(float output[4], int x, int y, void *data)
 
342
{
 
343
        MemoryBuffer *buffer = (MemoryBuffer *)data;
 
344
        buffer->readNoCheck(color, x, y);
 
345
}
 
346
 
 
347
void InverseSearchRadiusOperation::deinitializeTileData(rcti *rect, void *data) 
 
348
{
 
349
        if (data) {
 
350
                MemoryBuffer *mb = (MemoryBuffer *)data;
 
351
                delete mb;
 
352
        }
 
353
}
 
354
 
 
355
void InverseSearchRadiusOperation::deinitExecution() 
 
356
{
 
357
        this->m_inputRadius = NULL;
 
358
}
 
359
 
 
360
void InverseSearchRadiusOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
 
361
{
 
362
        NodeOperation::determineResolution(resolution, preferredResolution);
 
363
        resolution[0] = resolution[0] / DIVIDER;
 
364
        resolution[1] = resolution[1] / DIVIDER;
 
365
}
 
366
 
 
367
bool InverseSearchRadiusOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
 
368
{
 
369
        rcti newRect;
 
370
        newRect.ymin = input->ymin * DIVIDER - m_maxBlur;
 
371
        newRect.ymax = input->ymax * DIVIDER + m_maxBlur;
 
372
        newRect.xmin = input->xmin * DIVIDER - m_maxBlur;
 
373
        newRect.xmax = input->xmax * DIVIDER + m_maxBlur;
 
374
        return NodeOperation::determineDependingAreaOfInterest(&newRect, readOperation, output);
 
375
}
 
376
#endif