9a89fe21414dfa1ae3491f7e0884ad2d86d4ec22
[blender-staging.git] / source / blender / compositor / operations / COM_OpenCLKernels.cl
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 /// This file contains all opencl kernels for node-operation implementations 
24
25 // Global SAMPLERS
26 const sampler_t SAMPLER_NEAREST       = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;
27 const sampler_t SAMPLER_NEAREST_CLAMP = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;
28
29 __constant const int2 zero = {0,0};
30
31 // KERNEL --- BOKEH BLUR ---
32 __kernel void bokehBlurKernel(__read_only image2d_t boundingBox, __read_only image2d_t inputImage, 
33                               __read_only image2d_t bokehImage, __write_only image2d_t output, 
34                               int2 offsetInput, int2 offsetOutput, int radius, int step, int2 dimension, int2 offset) 
35 {
36         int2 coords = {get_global_id(0), get_global_id(1)}; 
37         coords += offset;
38         float tempBoundingBox;
39         float4 color = {0.0f,0.0f,0.0f,0.0f};
40         float4 multiplyer = {0.0f,0.0f,0.0f,0.0f};
41         float4 bokeh;
42         const float radius2 = radius*2.0f;
43         const int2 realCoordinate = coords + offsetOutput;
44
45         tempBoundingBox = read_imagef(boundingBox, SAMPLER_NEAREST, coords).s0;
46
47         if (tempBoundingBox > 0.0f && radius > 0 ) {
48                 const int2 bokehImageDim = get_image_dim(bokehImage);
49                 const int2 bokehImageCenter = bokehImageDim/2;
50                 const int2 minXY = max(realCoordinate - radius, zero);
51                 const int2 maxXY = min(realCoordinate + radius, dimension);
52                 int nx, ny;
53                 
54                 float2 uv;
55                 int2 inputXy;
56                 
57                 for (ny = minXY.y, inputXy.y = ny - offsetInput.y ; ny < maxXY.y ; ny +=step, inputXy.y+=step) {
58                         uv.y = ((realCoordinate.y-ny)/radius2)*bokehImageDim.y+bokehImageCenter.y;
59                         
60                         for (nx = minXY.x, inputXy.x = nx - offsetInput.x; nx < maxXY.x ; nx +=step, inputXy.x+=step) {
61                                 uv.x = ((realCoordinate.x-nx)/radius2)*bokehImageDim.x+bokehImageCenter.x;
62                                 bokeh = read_imagef(bokehImage, SAMPLER_NEAREST, uv);
63                                 color += bokeh * read_imagef(inputImage, SAMPLER_NEAREST, inputXy);
64                                 multiplyer += bokeh;
65                         }
66                 }
67                 color /= multiplyer;
68                 
69         } else {
70                 int2 imageCoordinates = realCoordinate - offsetInput;
71                 color = read_imagef(inputImage, SAMPLER_NEAREST, imageCoordinates);
72         }
73         
74         write_imagef(output, coords, color);
75 }
76
77 //KERNEL --- DEFOCUS /VARIABLESIZEBOKEHBLUR ---
78 __kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2d_t bokehImage, 
79                                         __read_only image2d_t inputSize,
80                                         __write_only image2d_t output, int2 offsetInput, int2 offsetOutput, 
81                                         int step, int maxBlur, float threshold, int2 dimension, int2 offset) 
82 {
83         float4 color = {1.0f, 0.0f, 0.0f, 1.0f};
84         int2 coords = {get_global_id(0), get_global_id(1)};
85         coords += offset;
86         const int2 realCoordinate = coords + offsetOutput;
87
88         float4 readColor;
89         float4 tempColor;
90         float4 bokeh;
91         float size;
92         float4 multiplier_accum = {1.0f, 1.0f, 1.0f, 1.0f};
93         float4 color_accum;
94         
95         int minx = max(realCoordinate.s0 - maxBlur, 0);
96         int miny = max(realCoordinate.s1 - maxBlur, 0);
97         int maxx = min(realCoordinate.s0 + maxBlur, dimension.s0);
98         int maxy = min(realCoordinate.s1 + maxBlur, dimension.s1);
99         
100         {
101                 int2 inputCoordinate = realCoordinate - offsetInput;
102                 float size_center = read_imagef(inputSize, SAMPLER_NEAREST, inputCoordinate).s0;
103                 color_accum = read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate);
104                 readColor = color_accum;
105
106                 if (size_center > threshold) {
107                         for (int ny = miny; ny < maxy; ny += step) {
108                                 inputCoordinate.s1 = ny - offsetInput.s1;
109                                 float dy = ny - realCoordinate.s1;
110                                 for (int nx = minx; nx < maxx; nx += step) {
111                                         float dx = nx - realCoordinate.s0;
112                                         if (dx != 0 || dy != 0) {
113                                                 inputCoordinate.s0 = nx - offsetInput.s0;
114                                                 size = read_imagef(inputSize, SAMPLER_NEAREST, inputCoordinate).s0;
115                                                 if (size > threshold) {
116                                                         if (size >= fabs(dx) && size >= fabs(dy)) {
117                                                                 float2 uv = {256.0f + dx * 255.0f / size,
118                                                                              256.0f + dy * 255.0f / size};
119                                                                 bokeh = read_imagef(bokehImage, SAMPLER_NEAREST, uv);
120                                                                 tempColor = read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate);
121                                                                 color_accum += bokeh * tempColor;
122                                                                 multiplier_accum += bokeh;
123                                                         }
124                                                 }
125                                         }
126                                 }
127                         } 
128                 }
129
130                 color = color_accum * (1.0f / multiplier_accum);
131                 
132                 /* blend in out values over the threshold, otherwise we get sharp, ugly transitions */
133                 if ((size_center > threshold) &&
134                     (size_center < threshold * 2.0f))
135                 {
136                         /* factor from 0-1 */
137                         float fac = (size_center - threshold) / threshold;
138                         color = (readColor * (1.0f - fac)) +  (color * fac);
139                 }
140                 
141                 write_imagef(output, coords, color);
142         }
143 }
144
145
146 // KERNEL --- DILATE ---
147 __kernel void dilateKernel(__read_only image2d_t inputImage,  __write_only image2d_t output,
148                            int2 offsetInput, int2 offsetOutput, int scope, int distanceSquared, int2 dimension, 
149                            int2 offset)
150 {
151         int2 coords = {get_global_id(0), get_global_id(1)}; 
152         coords += offset;
153         const int2 realCoordinate = coords + offsetOutput;
154
155         const int2 minXY = max(realCoordinate - scope, zero);
156         const int2 maxXY = min(realCoordinate + scope, dimension);
157         
158         float value = 0.0f;
159         int nx, ny;
160         int2 inputXy;
161         
162         for (ny = minXY.y, inputXy.y = ny - offsetInput.y ; ny < maxXY.y ; ny ++, inputXy.y++) {
163                 const float deltaY = (realCoordinate.y - ny);
164                 for (nx = minXY.x, inputXy.x = nx - offsetInput.x; nx < maxXY.x ; nx ++, inputXy.x++) {
165                         const float deltaX = (realCoordinate.x - nx);
166                         const float measuredDistance = deltaX * deltaX + deltaY * deltaY;
167                         if (measuredDistance <= distanceSquared) {
168                                 value = max(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0);
169                         }
170                 }
171         }
172
173         float4 color = {value,0.0f,0.0f,0.0f};
174         write_imagef(output, coords, color);
175 }
176
177 // KERNEL --- DILATE ---
178 __kernel void erodeKernel(__read_only image2d_t inputImage,  __write_only image2d_t output,
179                            int2 offsetInput, int2 offsetOutput, int scope, int distanceSquared, int2 dimension, 
180                            int2 offset)
181 {
182         int2 coords = {get_global_id(0), get_global_id(1)}; 
183         coords += offset;
184         const int2 realCoordinate = coords + offsetOutput;
185
186         const int2 minXY = max(realCoordinate - scope, zero);
187         const int2 maxXY = min(realCoordinate + scope, dimension);
188         
189         float value = 1.0f;
190         int nx, ny;
191         int2 inputXy;
192         
193         for (ny = minXY.y, inputXy.y = ny - offsetInput.y ; ny < maxXY.y ; ny ++, inputXy.y++) {
194                 for (nx = minXY.x, inputXy.x = nx - offsetInput.x; nx < maxXY.x ; nx ++, inputXy.x++) {
195                         const float deltaX = (realCoordinate.x - nx);
196                         const float deltaY = (realCoordinate.y - ny);
197                         const float measuredDistance = deltaX * deltaX+deltaY * deltaY;
198                         if (measuredDistance <= distanceSquared) {
199                                 value = min(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0);
200                         }
201                 }
202         }
203
204         float4 color = {value,0.0f,0.0f,0.0f};
205         write_imagef(output, coords, color);
206 }
207
208 // KERNEL --- DIRECTIONAL BLUR ---
209 __kernel void directionalBlurKernel(__read_only image2d_t inputImage,  __write_only image2d_t output,
210                            int2 offsetOutput, int iterations, float scale, float rotation, float2 translate,
211                            float2 center, int2 offset)
212 {
213         int2 coords = {get_global_id(0), get_global_id(1)}; 
214         coords += offset;
215         const int2 realCoordinate = coords + offsetOutput;
216
217         float4 col;
218         float2 ltxy = translate;
219         float lsc = scale;
220         float lrot = rotation;
221         
222         col = read_imagef(inputImage, SAMPLER_NEAREST, realCoordinate);
223
224         /* blur the image */
225         for (int i = 0; i < iterations; ++i) {
226                 const float cs = cos(lrot), ss = sin(lrot);
227                 const float isc = 1.0f / (1.0f + lsc);
228
229                 const float v = isc * (realCoordinate.s1 - center.s1) + ltxy.s1;
230                 const float u = isc * (realCoordinate.s0 - center.s0) + ltxy.s0;
231                 float2 uv = {
232                         cs * u + ss * v + center.s0,
233                         cs * v - ss * u + center.s1
234                 };
235
236                 col += read_imagef(inputImage, SAMPLER_NEAREST_CLAMP, uv);
237
238                 /* double transformations */
239                 ltxy += translate;
240                 lrot += rotation;
241                 lsc += scale;
242         }
243
244         col *= (1.0f/(iterations+1));
245
246         write_imagef(output, coords, col);
247 }