ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / kernel / kernels / cpu / kernel_cpu_image.h
1 /*
2  * Copyright 2011-2016 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __KERNEL_CPU_IMAGE_H__
18 #define __KERNEL_CPU_IMAGE_H__
19
20 CCL_NAMESPACE_BEGIN
21
22 template<typename T> struct TextureInterpolator {
23 #define SET_CUBIC_SPLINE_WEIGHTS(u, t) \
24   { \
25     u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \
26     u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \
27     u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \
28     u[3] = (1.0f / 6.0f) * t * t * t; \
29   } \
30   (void)0
31
32   static ccl_always_inline float4 read(float4 r)
33   {
34     return r;
35   }
36
37   static ccl_always_inline float4 read(uchar4 r)
38   {
39     float f = 1.0f / 255.0f;
40     return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
41   }
42
43   static ccl_always_inline float4 read(uchar r)
44   {
45     float f = r * (1.0f / 255.0f);
46     return make_float4(f, f, f, 1.0f);
47   }
48
49   static ccl_always_inline float4 read(float r)
50   {
51     /* TODO(dingto): Optimize this, so interpolation
52      * happens on float instead of float4 */
53     return make_float4(r, r, r, 1.0f);
54   }
55
56   static ccl_always_inline float4 read(half4 r)
57   {
58     return half4_to_float4(r);
59   }
60
61   static ccl_always_inline float4 read(half r)
62   {
63     float f = half_to_float(r);
64     return make_float4(f, f, f, 1.0f);
65   }
66
67   static ccl_always_inline float4 read(uint16_t r)
68   {
69     float f = r * (1.0f / 65535.0f);
70     return make_float4(f, f, f, 1.0f);
71   }
72
73   static ccl_always_inline float4 read(ushort4 r)
74   {
75     float f = 1.0f / 65535.0f;
76     return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
77   }
78
79   static ccl_always_inline float4 read(const T *data, int x, int y, int width, int height)
80   {
81     if (x < 0 || y < 0 || x >= width || y >= height) {
82       return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
83     }
84     return read(data[y * width + x]);
85   }
86
87   static ccl_always_inline int wrap_periodic(int x, int width)
88   {
89     x %= width;
90     if (x < 0)
91       x += width;
92     return x;
93   }
94
95   static ccl_always_inline int wrap_clamp(int x, int width)
96   {
97     return clamp(x, 0, width - 1);
98   }
99
100   static ccl_always_inline float frac(float x, int *ix)
101   {
102     int i = float_to_int(x) - ((x < 0.0f) ? 1 : 0);
103     *ix = i;
104     return x - (float)i;
105   }
106
107   /* ********  2D interpolation ******** */
108
109   static ccl_always_inline float4 interp_closest(const TextureInfo &info, float x, float y)
110   {
111     const T *data = (const T *)info.data;
112     const int width = info.width;
113     const int height = info.height;
114     int ix, iy;
115     frac(x * (float)width, &ix);
116     frac(y * (float)height, &iy);
117     switch (info.extension) {
118       case EXTENSION_REPEAT:
119         ix = wrap_periodic(ix, width);
120         iy = wrap_periodic(iy, height);
121         break;
122       case EXTENSION_CLIP:
123         if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
124           return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
125         }
126         ATTR_FALLTHROUGH;
127       case EXTENSION_EXTEND:
128         ix = wrap_clamp(ix, width);
129         iy = wrap_clamp(iy, height);
130         break;
131       default:
132         kernel_assert(0);
133         return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
134     }
135     return read(data[ix + iy * width]);
136   }
137
138   static ccl_always_inline float4 interp_linear(const TextureInfo &info, float x, float y)
139   {
140     const T *data = (const T *)info.data;
141     const int width = info.width;
142     const int height = info.height;
143     int ix, iy, nix, niy;
144     const float tx = frac(x * (float)width - 0.5f, &ix);
145     const float ty = frac(y * (float)height - 0.5f, &iy);
146     switch (info.extension) {
147       case EXTENSION_REPEAT:
148         ix = wrap_periodic(ix, width);
149         iy = wrap_periodic(iy, height);
150         nix = wrap_periodic(ix + 1, width);
151         niy = wrap_periodic(iy + 1, height);
152         break;
153       case EXTENSION_CLIP:
154         nix = ix + 1;
155         niy = iy + 1;
156         break;
157       case EXTENSION_EXTEND:
158         nix = wrap_clamp(ix + 1, width);
159         niy = wrap_clamp(iy + 1, height);
160         ix = wrap_clamp(ix, width);
161         iy = wrap_clamp(iy, height);
162         break;
163       default:
164         kernel_assert(0);
165         return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
166     }
167     return (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, width, height) +
168            (1.0f - ty) * tx * read(data, nix, iy, width, height) +
169            ty * (1.0f - tx) * read(data, ix, niy, width, height) +
170            ty * tx * read(data, nix, niy, width, height);
171   }
172
173   static ccl_always_inline float4 interp_cubic(const TextureInfo &info, float x, float y)
174   {
175     const T *data = (const T *)info.data;
176     const int width = info.width;
177     const int height = info.height;
178     int ix, iy, nix, niy;
179     const float tx = frac(x * (float)width - 0.5f, &ix);
180     const float ty = frac(y * (float)height - 0.5f, &iy);
181     int pix, piy, nnix, nniy;
182     switch (info.extension) {
183       case EXTENSION_REPEAT:
184         ix = wrap_periodic(ix, width);
185         iy = wrap_periodic(iy, height);
186         pix = wrap_periodic(ix - 1, width);
187         piy = wrap_periodic(iy - 1, height);
188         nix = wrap_periodic(ix + 1, width);
189         niy = wrap_periodic(iy + 1, height);
190         nnix = wrap_periodic(ix + 2, width);
191         nniy = wrap_periodic(iy + 2, height);
192         break;
193       case EXTENSION_CLIP:
194         pix = ix - 1;
195         piy = iy - 1;
196         nix = ix + 1;
197         niy = iy + 1;
198         nnix = ix + 2;
199         nniy = iy + 2;
200         break;
201       case EXTENSION_EXTEND:
202         pix = wrap_clamp(ix - 1, width);
203         piy = wrap_clamp(iy - 1, height);
204         nix = wrap_clamp(ix + 1, width);
205         niy = wrap_clamp(iy + 1, height);
206         nnix = wrap_clamp(ix + 2, width);
207         nniy = wrap_clamp(iy + 2, height);
208         ix = wrap_clamp(ix, width);
209         iy = wrap_clamp(iy, height);
210         break;
211       default:
212         kernel_assert(0);
213         return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
214     }
215     const int xc[4] = {pix, ix, nix, nnix};
216     const int yc[4] = {piy, iy, niy, nniy};
217     float u[4], v[4];
218     /* Some helper macro to keep code reasonable size,
219      * let compiler to inline all the matrix multiplications.
220      */
221 #define DATA(x, y) (read(data, xc[x], yc[y], width, height))
222 #define TERM(col) \
223   (v[col] * \
224    (u[0] * DATA(0, col) + u[1] * DATA(1, col) + u[2] * DATA(2, col) + u[3] * DATA(3, col)))
225
226     SET_CUBIC_SPLINE_WEIGHTS(u, tx);
227     SET_CUBIC_SPLINE_WEIGHTS(v, ty);
228
229     /* Actual interpolation. */
230     return TERM(0) + TERM(1) + TERM(2) + TERM(3);
231 #undef TERM
232 #undef DATA
233   }
234
235   static ccl_always_inline float4 interp(const TextureInfo &info, float x, float y)
236   {
237     if (UNLIKELY(!info.data)) {
238       return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
239     }
240     switch (info.interpolation) {
241       case INTERPOLATION_CLOSEST:
242         return interp_closest(info, x, y);
243       case INTERPOLATION_LINEAR:
244         return interp_linear(info, x, y);
245       default:
246         return interp_cubic(info, x, y);
247     }
248   }
249
250   /* ********  3D interpolation ******** */
251
252   static ccl_always_inline float4 interp_3d_closest(const TextureInfo &info,
253                                                     float x,
254                                                     float y,
255                                                     float z)
256   {
257     int width = info.width;
258     int height = info.height;
259     int depth = info.depth;
260     int ix, iy, iz;
261
262     frac(x * (float)width, &ix);
263     frac(y * (float)height, &iy);
264     frac(z * (float)depth, &iz);
265
266     switch (info.extension) {
267       case EXTENSION_REPEAT:
268         ix = wrap_periodic(ix, width);
269         iy = wrap_periodic(iy, height);
270         iz = wrap_periodic(iz, depth);
271         break;
272       case EXTENSION_CLIP:
273         if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) {
274           return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
275         }
276         ATTR_FALLTHROUGH;
277       case EXTENSION_EXTEND:
278         ix = wrap_clamp(ix, width);
279         iy = wrap_clamp(iy, height);
280         iz = wrap_clamp(iz, depth);
281         break;
282       default:
283         kernel_assert(0);
284         return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
285     }
286
287     const T *data = (const T *)info.data;
288     return read(data[ix + iy * width + iz * width * height]);
289   }
290
291   static ccl_always_inline float4 interp_3d_linear(const TextureInfo &info,
292                                                    float x,
293                                                    float y,
294                                                    float z)
295   {
296     int width = info.width;
297     int height = info.height;
298     int depth = info.depth;
299     int ix, iy, iz;
300     int nix, niy, niz;
301
302     float tx = frac(x * (float)width - 0.5f, &ix);
303     float ty = frac(y * (float)height - 0.5f, &iy);
304     float tz = frac(z * (float)depth - 0.5f, &iz);
305
306     switch (info.extension) {
307       case EXTENSION_REPEAT:
308         ix = wrap_periodic(ix, width);
309         iy = wrap_periodic(iy, height);
310         iz = wrap_periodic(iz, depth);
311
312         nix = wrap_periodic(ix + 1, width);
313         niy = wrap_periodic(iy + 1, height);
314         niz = wrap_periodic(iz + 1, depth);
315         break;
316       case EXTENSION_CLIP:
317         if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) {
318           return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
319         }
320         ATTR_FALLTHROUGH;
321       case EXTENSION_EXTEND:
322         nix = wrap_clamp(ix + 1, width);
323         niy = wrap_clamp(iy + 1, height);
324         niz = wrap_clamp(iz + 1, depth);
325
326         ix = wrap_clamp(ix, width);
327         iy = wrap_clamp(iy, height);
328         iz = wrap_clamp(iz, depth);
329         break;
330       default:
331         kernel_assert(0);
332         return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
333     }
334
335     const T *data = (const T *)info.data;
336     float4 r;
337
338     r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) *
339         read(data[ix + iy * width + iz * width * height]);
340     r += (1.0f - tz) * (1.0f - ty) * tx * read(data[nix + iy * width + iz * width * height]);
341     r += (1.0f - tz) * ty * (1.0f - tx) * read(data[ix + niy * width + iz * width * height]);
342     r += (1.0f - tz) * ty * tx * read(data[nix + niy * width + iz * width * height]);
343
344     r += tz * (1.0f - ty) * (1.0f - tx) * read(data[ix + iy * width + niz * width * height]);
345     r += tz * (1.0f - ty) * tx * read(data[nix + iy * width + niz * width * height]);
346     r += tz * ty * (1.0f - tx) * read(data[ix + niy * width + niz * width * height]);
347     r += tz * ty * tx * read(data[nix + niy * width + niz * width * height]);
348
349     return r;
350   }
351
352   /* TODO(sergey): For some unspeakable reason both GCC-6 and Clang-3.9 are
353    * causing stack overflow issue in this function unless it is inlined.
354    *
355    * Only happens for AVX2 kernel and global __KERNEL_SSE__ vectorization
356    * enabled.
357    */
358 #if defined(__GNUC__) || defined(__clang__)
359   static ccl_always_inline
360 #else
361   static ccl_never_inline
362 #endif
363       float4
364       interp_3d_tricubic(const TextureInfo &info, float x, float y, float z)
365   {
366     int width = info.width;
367     int height = info.height;
368     int depth = info.depth;
369     int ix, iy, iz;
370     int nix, niy, niz;
371     /* Tricubic b-spline interpolation. */
372     const float tx = frac(x * (float)width - 0.5f, &ix);
373     const float ty = frac(y * (float)height - 0.5f, &iy);
374     const float tz = frac(z * (float)depth - 0.5f, &iz);
375     int pix, piy, piz, nnix, nniy, nniz;
376
377     switch (info.extension) {
378       case EXTENSION_REPEAT:
379         ix = wrap_periodic(ix, width);
380         iy = wrap_periodic(iy, height);
381         iz = wrap_periodic(iz, depth);
382
383         pix = wrap_periodic(ix - 1, width);
384         piy = wrap_periodic(iy - 1, height);
385         piz = wrap_periodic(iz - 1, depth);
386
387         nix = wrap_periodic(ix + 1, width);
388         niy = wrap_periodic(iy + 1, height);
389         niz = wrap_periodic(iz + 1, depth);
390
391         nnix = wrap_periodic(ix + 2, width);
392         nniy = wrap_periodic(iy + 2, height);
393         nniz = wrap_periodic(iz + 2, depth);
394         break;
395       case EXTENSION_CLIP:
396         if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) {
397           return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
398         }
399         ATTR_FALLTHROUGH;
400       case EXTENSION_EXTEND:
401         pix = wrap_clamp(ix - 1, width);
402         piy = wrap_clamp(iy - 1, height);
403         piz = wrap_clamp(iz - 1, depth);
404
405         nix = wrap_clamp(ix + 1, width);
406         niy = wrap_clamp(iy + 1, height);
407         niz = wrap_clamp(iz + 1, depth);
408
409         nnix = wrap_clamp(ix + 2, width);
410         nniy = wrap_clamp(iy + 2, height);
411         nniz = wrap_clamp(iz + 2, depth);
412
413         ix = wrap_clamp(ix, width);
414         iy = wrap_clamp(iy, height);
415         iz = wrap_clamp(iz, depth);
416         break;
417       default:
418         kernel_assert(0);
419         return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
420     }
421
422     const int xc[4] = {pix, ix, nix, nnix};
423     const int yc[4] = {width * piy, width * iy, width * niy, width * nniy};
424     const int zc[4] = {
425         width * height * piz, width * height * iz, width * height * niz, width * height * nniz};
426     float u[4], v[4], w[4];
427
428     /* Some helper macro to keep code reasonable size,
429      * let compiler to inline all the matrix multiplications.
430      */
431 #define DATA(x, y, z) (read(data[xc[x] + yc[y] + zc[z]]))
432 #define COL_TERM(col, row) \
433   (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \
434              u[3] * DATA(3, col, row)))
435 #define ROW_TERM(row) \
436   (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
437
438     SET_CUBIC_SPLINE_WEIGHTS(u, tx);
439     SET_CUBIC_SPLINE_WEIGHTS(v, ty);
440     SET_CUBIC_SPLINE_WEIGHTS(w, tz);
441
442     /* Actual interpolation. */
443     const T *data = (const T *)info.data;
444     return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
445
446 #undef COL_TERM
447 #undef ROW_TERM
448 #undef DATA
449   }
450
451   static ccl_always_inline float4
452   interp_3d(const TextureInfo &info, float x, float y, float z, InterpolationType interp)
453   {
454     if (UNLIKELY(!info.data))
455       return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
456
457     switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
458       case INTERPOLATION_CLOSEST:
459         return interp_3d_closest(info, x, y, z);
460       case INTERPOLATION_LINEAR:
461         return interp_3d_linear(info, x, y, z);
462       default:
463         return interp_3d_tricubic(info, x, y, z);
464     }
465   }
466 #undef SET_CUBIC_SPLINE_WEIGHTS
467 };
468
469 ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y)
470 {
471   const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
472
473   switch (kernel_tex_type(id)) {
474     case IMAGE_DATA_TYPE_HALF:
475       return TextureInterpolator<half>::interp(info, x, y);
476     case IMAGE_DATA_TYPE_BYTE:
477       return TextureInterpolator<uchar>::interp(info, x, y);
478     case IMAGE_DATA_TYPE_USHORT:
479       return TextureInterpolator<uint16_t>::interp(info, x, y);
480     case IMAGE_DATA_TYPE_FLOAT:
481       return TextureInterpolator<float>::interp(info, x, y);
482     case IMAGE_DATA_TYPE_HALF4:
483       return TextureInterpolator<half4>::interp(info, x, y);
484     case IMAGE_DATA_TYPE_BYTE4:
485       return TextureInterpolator<uchar4>::interp(info, x, y);
486     case IMAGE_DATA_TYPE_USHORT4:
487       return TextureInterpolator<ushort4>::interp(info, x, y);
488     case IMAGE_DATA_TYPE_FLOAT4:
489       return TextureInterpolator<float4>::interp(info, x, y);
490     default:
491       assert(0);
492       return make_float4(
493           TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
494   }
495 }
496
497 ccl_device float4 kernel_tex_image_interp_3d(
498     KernelGlobals *kg, int id, float x, float y, float z, InterpolationType interp)
499 {
500   const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
501
502   switch (kernel_tex_type(id)) {
503     case IMAGE_DATA_TYPE_HALF:
504       return TextureInterpolator<half>::interp_3d(info, x, y, z, interp);
505     case IMAGE_DATA_TYPE_BYTE:
506       return TextureInterpolator<uchar>::interp_3d(info, x, y, z, interp);
507     case IMAGE_DATA_TYPE_USHORT:
508       return TextureInterpolator<uint16_t>::interp_3d(info, x, y, z, interp);
509     case IMAGE_DATA_TYPE_FLOAT:
510       return TextureInterpolator<float>::interp_3d(info, x, y, z, interp);
511     case IMAGE_DATA_TYPE_HALF4:
512       return TextureInterpolator<half4>::interp_3d(info, x, y, z, interp);
513     case IMAGE_DATA_TYPE_BYTE4:
514       return TextureInterpolator<uchar4>::interp_3d(info, x, y, z, interp);
515     case IMAGE_DATA_TYPE_USHORT4:
516       return TextureInterpolator<ushort4>::interp_3d(info, x, y, z, interp);
517     case IMAGE_DATA_TYPE_FLOAT4:
518       return TextureInterpolator<float4>::interp_3d(info, x, y, z, interp);
519     default:
520       assert(0);
521       return make_float4(
522           TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
523   }
524 }
525
526 CCL_NAMESPACE_END
527
528 #endif  // __KERNEL_CPU_IMAGE_H__