Blender V4.5
cycles/kernel/device/cpu/image.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
9
10#ifdef WITH_NANOVDB
11# include "kernel/util/nanovdb.h"
12#endif
13
14#include "util/half.h"
15
17
18/* Make template functions private so symbols don't conflict between kernels with different
19 * instruction sets. */
20namespace {
21
22#define SET_CUBIC_SPLINE_WEIGHTS(u, t) \
23 { \
24 u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \
25 u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \
26 u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \
27 u[3] = (1.0f / 6.0f) * t * t * t; \
28 } \
29 (void)0
30
31ccl_device_inline float frac(const float x, int *ix)
32{
33 int i = float_to_int(x) - ((x < 0.0f) ? 1 : 0);
34 *ix = i;
35 return x - (float)i;
36}
37
38template<typename TexT, typename OutT = float4> struct TextureInterpolator {
39
40 static ccl_always_inline OutT zero()
41 {
42 if constexpr (std::is_same_v<OutT, float4>) {
43 return zero_float4();
44 }
45 else {
46 return 0.0f;
47 }
48 }
49
51 {
52 return r;
53 }
54
56 {
57 const float f = 1.0f / 255.0f;
58 return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
59 }
60
61 static ccl_always_inline float read(const uchar r)
62 {
63 return r * (1.0f / 255.0f);
64 }
65
66 static ccl_always_inline float read(const float r)
67 {
68 return r;
69 }
70
72 {
73 return half4_to_float4_image(r);
74 }
75
76 static ccl_always_inline float read(half r)
77 {
78 return half_to_float_image(r);
79 }
80
81 static ccl_always_inline float read(const uint16_t r)
82 {
83 return r * (1.0f / 65535.0f);
84 }
85
87 {
88 const float f = 1.0f / 65535.0f;
89 return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
90 }
91
92 /* Read 2D Texture Data
93 * Does not check if data request is in bounds. */
94 static ccl_always_inline OutT
95 read(const TexT *data, const int x, int y, const int width, const int height)
96 {
97 return read(data[y * width + x]);
98 }
99
100 /* Read 2D Texture Data Clip
101 * Returns transparent black if data request is out of bounds. */
102 static ccl_always_inline OutT
103 read_clip(const TexT *data, const int x, int y, const int width, const int height)
104 {
105 if (x < 0 || x >= width || y < 0 || y >= height) {
106 return zero();
107 }
108 return read(data[y * width + x]);
109 }
110
111 /* Read 3D Texture Data
112 * Does not check if data request is in bounds. */
113 static ccl_always_inline OutT read(const TexT *data,
114 const int x,
115 int y,
116 const int z,
117 int width,
118 const int height,
119 const int depth)
120 {
121 return read(data[x + y * width + z * width * height]);
122 }
123
124 /* Read 3D Texture Data Clip
125 * Returns transparent black if data request is out of bounds. */
126 static ccl_always_inline OutT read_clip(const TexT *data,
127 const int x,
128 int y,
129 const int z,
130 int width,
131 const int height,
132 const int depth)
133 {
134 if (x < 0 || x >= width || y < 0 || y >= height || z < 0 || z >= depth) {
135 return zero();
136 }
137 return read(data[x + y * width + z * width * height]);
138 }
139
140 /* Trilinear Interpolation */
141 static ccl_always_inline OutT
143 const float tx,
144 const float ty,
145 const float tz,
146 const int ix,
147 const int iy,
148 const int iz,
149 const int nix,
150 const int niy,
151 const int niz,
152 const int width,
153 const int height,
154 const int depth,
155 OutT read(const TexT *, int, int, int, int, int, int))
156 {
157 OutT r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) *
158 read(data, ix, iy, iz, width, height, depth);
159 r += (1.0f - tz) * (1.0f - ty) * tx * read(data, nix, iy, iz, width, height, depth);
160 r += (1.0f - tz) * ty * (1.0f - tx) * read(data, ix, niy, iz, width, height, depth);
161 r += (1.0f - tz) * ty * tx * read(data, nix, niy, iz, width, height, depth);
162
163 r += tz * (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, niz, width, height, depth);
164 r += tz * (1.0f - ty) * tx * read(data, nix, iy, niz, width, height, depth);
165 r += tz * ty * (1.0f - tx) * read(data, ix, niy, niz, width, height, depth);
166 r += tz * ty * tx * read(data, nix, niy, niz, width, height, depth);
167 return r;
168 }
169
171 static ccl_always_inline OutT
173 const float tx,
174 const float ty,
175 const float tz,
176 const int xc[4],
177 const int yc[4],
178 const int zc[4],
179 const int width,
180 const int height,
181 const int depth,
182 OutT read(const TexT *, int, int, int, int, int, int))
183 {
184 float u[4], v[4], w[4];
185
186 /* Some helper macros to keep code size reasonable.
187 * Lets the compiler inline all the matrix multiplications.
188 */
189#define DATA(x, y, z) (read(data, xc[x], yc[y], zc[z], width, height, depth))
190#define COL_TERM(col, row) \
191 (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \
192 u[3] * DATA(3, col, row)))
193#define ROW_TERM(row) \
194 (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
195
199 /* Actual interpolation. */
200 return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
201
202#undef COL_TERM
203#undef ROW_TERM
204#undef DATA
205 }
206
207 static ccl_always_inline int wrap_periodic(int x, const int width)
208 {
209 x %= width;
210 if (x < 0) {
211 x += width;
212 }
213 return x;
214 }
215
216 static ccl_always_inline int wrap_clamp(const int x, const int width)
217 {
218 return clamp(x, 0, width - 1);
219 }
220
221 static ccl_always_inline int wrap_mirror(const int x, const int width)
222 {
223 const int m = abs(x + (x < 0)) % (2 * width);
224 if (m >= width) {
225 return 2 * width - m - 1;
226 }
227 return m;
228 }
229
230 /* ******** 2D interpolation ******** */
231
232 static ccl_always_inline OutT interp_closest(const TextureInfo &info, const float x, float y)
233 {
234 const int width = info.width;
235 const int height = info.height;
236 int ix, iy;
237 frac(x * (float)width, &ix);
238 frac(y * (float)height, &iy);
239 switch (info.extension) {
240 case EXTENSION_REPEAT:
241 ix = wrap_periodic(ix, width);
242 iy = wrap_periodic(iy, height);
243 break;
244 case EXTENSION_CLIP:
245 /* No samples are inside the clip region. */
246 if (ix < 0 || ix >= width || iy < 0 || iy >= height) {
247 return zero();
248 }
249 break;
250 case EXTENSION_EXTEND:
251 ix = wrap_clamp(ix, width);
252 iy = wrap_clamp(iy, height);
253 break;
254 case EXTENSION_MIRROR:
255 ix = wrap_mirror(ix, width);
256 iy = wrap_mirror(iy, height);
257 break;
258 default:
259 kernel_assert(0);
260 return zero();
261 }
262
263 const TexT *data = (const TexT *)info.data;
264 return read(data, ix, iy, width, height);
265 }
266
267 static ccl_always_inline OutT interp_linear(const TextureInfo &info, const float x, float y)
268 {
269 const int width = info.width;
270 const int height = info.height;
271
272 /* A -0.5 offset is used to center the linear samples around the sample point. */
273 int ix, iy;
274 int nix, niy;
275 const float tx = frac(x * (float)width - 0.5f, &ix);
276 const float ty = frac(y * (float)height - 0.5f, &iy);
277 const TexT *data = (const TexT *)info.data;
278
279 switch (info.extension) {
280 case EXTENSION_REPEAT:
281 ix = wrap_periodic(ix, width);
282 nix = wrap_periodic(ix + 1, width);
283
284 iy = wrap_periodic(iy, height);
285 niy = wrap_periodic(iy + 1, height);
286 break;
287 case EXTENSION_CLIP:
288 /* No linear samples are inside the clip region. */
289 if (ix < -1 || ix >= width || iy < -1 || iy >= height) {
290 return zero();
291 }
292 nix = ix + 1;
293 niy = iy + 1;
294 return (1.0f - ty) * (1.0f - tx) * read_clip(data, ix, iy, width, height) +
295 (1.0f - ty) * tx * read_clip(data, nix, iy, width, height) +
296 ty * (1.0f - tx) * read_clip(data, ix, niy, width, height) +
297 ty * tx * read_clip(data, nix, niy, width, height);
298 case EXTENSION_EXTEND:
299 nix = wrap_clamp(ix + 1, width);
300 ix = wrap_clamp(ix, width);
301 niy = wrap_clamp(iy + 1, height);
302 iy = wrap_clamp(iy, height);
303 break;
304 case EXTENSION_MIRROR:
305 nix = wrap_mirror(ix + 1, width);
306 ix = wrap_mirror(ix, width);
307 niy = wrap_mirror(iy + 1, height);
308 iy = wrap_mirror(iy, height);
309 break;
310 default:
311 kernel_assert(0);
312 return zero();
313 }
314
315 return (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, width, height) +
316 (1.0f - ty) * tx * read(data, nix, iy, width, height) +
317 ty * (1.0f - tx) * read(data, ix, niy, width, height) +
318 ty * tx * read(data, nix, niy, width, height);
319 }
320
321 static ccl_always_inline OutT interp_cubic(const TextureInfo &info, const float x, float y)
322 {
323 const int width = info.width;
324 const int height = info.height;
325
326 /* A -0.5 offset is used to center the cubic samples around the sample point. */
327 int ix, iy;
328 const float tx = frac(x * (float)width - 0.5f, &ix);
329 const float ty = frac(y * (float)height - 0.5f, &iy);
330
331 int pix, piy;
332 int nix, niy;
333 int nnix, nniy;
334
335 switch (info.extension) {
336 case EXTENSION_REPEAT:
337 ix = wrap_periodic(ix, width);
338 pix = wrap_periodic(ix - 1, width);
339 nix = wrap_periodic(ix + 1, width);
340 nnix = wrap_periodic(ix + 2, width);
341
342 iy = wrap_periodic(iy, height);
343 piy = wrap_periodic(iy - 1, height);
344 niy = wrap_periodic(iy + 1, height);
345 nniy = wrap_periodic(iy + 2, height);
346 break;
347 case EXTENSION_CLIP:
348 /* No cubic samples are inside the clip region. */
349 if (ix < -2 || ix > width || iy < -2 || iy > height) {
350 return zero();
351 }
352
353 pix = ix - 1;
354 nix = ix + 1;
355 nnix = ix + 2;
356
357 piy = iy - 1;
358 niy = iy + 1;
359 nniy = iy + 2;
360 break;
361 case EXTENSION_EXTEND:
362 pix = wrap_clamp(ix - 1, width);
363 nix = wrap_clamp(ix + 1, width);
364 nnix = wrap_clamp(ix + 2, width);
365 ix = wrap_clamp(ix, width);
366
367 piy = wrap_clamp(iy - 1, height);
368 niy = wrap_clamp(iy + 1, height);
369 nniy = wrap_clamp(iy + 2, height);
370 iy = wrap_clamp(iy, height);
371 break;
372 case EXTENSION_MIRROR:
373 pix = wrap_mirror(ix - 1, width);
374 nix = wrap_mirror(ix + 1, width);
375 nnix = wrap_mirror(ix + 2, width);
376 ix = wrap_mirror(ix, width);
377
378 piy = wrap_mirror(iy - 1, height);
379 niy = wrap_mirror(iy + 1, height);
380 nniy = wrap_mirror(iy + 2, height);
381 iy = wrap_mirror(iy, height);
382 break;
383 default:
384 kernel_assert(0);
385 return zero();
386 }
387
388 const TexT *data = (const TexT *)info.data;
389 const int xc[4] = {pix, ix, nix, nnix};
390 const int yc[4] = {piy, iy, niy, nniy};
391 float u[4], v[4];
392
393 /* Some helper macros to keep code size reasonable.
394 * Lets the compiler inline all the matrix multiplications.
395 */
396#define DATA(x, y) (read_clip(data, xc[x], yc[y], width, height))
397#define TERM(col) \
398 (v[col] * \
399 (u[0] * DATA(0, col) + u[1] * DATA(1, col) + u[2] * DATA(2, col) + u[3] * DATA(3, col)))
400
403
404 /* Actual interpolation. */
405 return TERM(0) + TERM(1) + TERM(2) + TERM(3);
406#undef TERM
407#undef DATA
408 }
409
410 static ccl_always_inline OutT interp(const TextureInfo &info, const float x, float y)
411 {
412 switch (info.interpolation) {
414 return interp_closest(info, x, y);
416 return interp_linear(info, x, y);
417 default:
418 return interp_cubic(info, x, y);
419 }
420 }
421
422 /* ******** 3D interpolation ******** */
423
425 const float x,
426 const float y,
427 const float z)
428 {
429 const int width = info.width;
430 const int height = info.height;
431 const int depth = info.depth;
432 int ix, iy, iz;
433
434 frac(x * (float)width, &ix);
435 frac(y * (float)height, &iy);
436 frac(z * (float)depth, &iz);
437
438 switch (info.extension) {
439 case EXTENSION_REPEAT:
440 ix = wrap_periodic(ix, width);
441 iy = wrap_periodic(iy, height);
442 iz = wrap_periodic(iz, depth);
443 break;
444 case EXTENSION_CLIP:
445 /* No samples are inside the clip region. */
446 if (ix < 0 || ix >= width || iy < 0 || iy >= height || iz < 0 || iz >= depth) {
447 return zero();
448 }
449 break;
450 case EXTENSION_EXTEND:
451 ix = wrap_clamp(ix, width);
452 iy = wrap_clamp(iy, height);
453 iz = wrap_clamp(iz, depth);
454 break;
455 case EXTENSION_MIRROR:
456 ix = wrap_mirror(ix, width);
457 iy = wrap_mirror(iy, height);
458 iz = wrap_mirror(iz, depth);
459 break;
460 default:
461 kernel_assert(0);
462 return zero();
463 }
464
465 const TexT *data = (const TexT *)info.data;
466 return read(data, ix, iy, iz, width, height, depth);
467 }
468
470 const float x,
471 const float y,
472 const float z)
473 {
474 const int width = info.width;
475 const int height = info.height;
476 const int depth = info.depth;
477 int ix, iy, iz;
478 int nix, niy, niz;
479
480 /* A -0.5 offset is used to center the linear samples around the sample point. */
481 float tx = frac(x * (float)width - 0.5f, &ix);
482 float ty = frac(y * (float)height - 0.5f, &iy);
483 float tz = frac(z * (float)depth - 0.5f, &iz);
484
485 switch (info.extension) {
486 case EXTENSION_REPEAT:
487 ix = wrap_periodic(ix, width);
488 nix = wrap_periodic(ix + 1, width);
489
490 iy = wrap_periodic(iy, height);
491 niy = wrap_periodic(iy + 1, height);
492
493 iz = wrap_periodic(iz, depth);
494 niz = wrap_periodic(iz + 1, depth);
495 break;
496 case EXTENSION_CLIP:
497 /* No linear samples are inside the clip region. */
498 if (ix < -1 || ix >= width || iy < -1 || iy >= height || iz < -1 || iz >= depth) {
499 return zero();
500 }
501
502 nix = ix + 1;
503 niy = iy + 1;
504 niz = iz + 1;
505
506 /* All linear samples are inside the clip region. */
507 if (ix >= 0 && nix < width && iy >= 0 && niy < height && iz >= 0 && niz < depth) {
508 break;
509 }
510
511 /* The linear samples span the clip border.
512 * #read_clip is used to ensure proper interpolation across the clip border. */
513 return trilinear_lookup((const TexT *)info.data,
514 tx,
515 ty,
516 tz,
517 ix,
518 iy,
519 iz,
520 nix,
521 niy,
522 niz,
523 width,
524 height,
525 depth,
526 read_clip);
527 case EXTENSION_EXTEND:
528 nix = wrap_clamp(ix + 1, width);
529 ix = wrap_clamp(ix, width);
530
531 niy = wrap_clamp(iy + 1, height);
532 iy = wrap_clamp(iy, height);
533
534 niz = wrap_clamp(iz + 1, depth);
535 iz = wrap_clamp(iz, depth);
536 break;
537 case EXTENSION_MIRROR:
538 nix = wrap_mirror(ix + 1, width);
539 ix = wrap_mirror(ix, width);
540
541 niy = wrap_mirror(iy + 1, height);
542 iy = wrap_mirror(iy, height);
543
544 niz = wrap_mirror(iz + 1, depth);
545 iz = wrap_mirror(iz, depth);
546 break;
547 default:
548 kernel_assert(0);
549 return zero();
550 }
551
552 return trilinear_lookup((const TexT *)info.data,
553 tx,
554 ty,
555 tz,
556 ix,
557 iy,
558 iz,
559 nix,
560 niy,
561 niz,
562 width,
563 height,
564 depth,
565 read);
566 }
567
568 /* Tricubic b-spline interpolation.
569 *
570 * TODO(sergey): For some unspeakable reason both GCC-6 and Clang-3.9 are
571 * causing stack overflow issue in this function unless it is inlined.
572 *
573 * Only happens for AVX2 kernel and global __KERNEL_SSE__ vectorization
574 * enabled.
575 */
576#if defined(__GNUC__) || defined(__clang__)
577 static ccl_always_inline
578#else
579 static ccl_never_inline
580#endif
581 OutT
582 interp_3d_cubic(const TextureInfo &info, const float x, float y, const float z)
583 {
584 int width = info.width;
585 int height = info.height;
586 int depth = info.depth;
587 int ix, iy, iz;
588
589 /* A -0.5 offset is used to center the cubic samples around the sample point. */
590 const float tx = frac(x * (float)width - 0.5f, &ix);
591 const float ty = frac(y * (float)height - 0.5f, &iy);
592 const float tz = frac(z * (float)depth - 0.5f, &iz);
593
594 int pix, piy, piz;
595 int nix, niy, niz;
596 int nnix, nniy, nniz;
597
598 switch (info.extension) {
599 case EXTENSION_REPEAT:
600 ix = wrap_periodic(ix, width);
601 pix = wrap_periodic(ix - 1, width);
602 nix = wrap_periodic(ix + 1, width);
603 nnix = wrap_periodic(ix + 2, width);
604
605 iy = wrap_periodic(iy, height);
606 niy = wrap_periodic(iy + 1, height);
607 piy = wrap_periodic(iy - 1, height);
608 nniy = wrap_periodic(iy + 2, height);
609
610 iz = wrap_periodic(iz, depth);
611 piz = wrap_periodic(iz - 1, depth);
612 niz = wrap_periodic(iz + 1, depth);
613 nniz = wrap_periodic(iz + 2, depth);
614 break;
615 case EXTENSION_CLIP: {
616 /* No cubic samples are inside the clip region. */
617 if (ix < -2 || ix > width || iy < -2 || iy > height || iz < -2 || iz > depth) {
618 return zero();
619 }
620
621 pix = ix - 1;
622 nnix = ix + 2;
623 nix = ix + 1;
624
625 piy = iy - 1;
626 niy = iy + 1;
627 nniy = iy + 2;
628
629 piz = iz - 1;
630 niz = iz + 1;
631 nniz = iz + 2;
632
633 /* All cubic samples are inside the clip region. */
634 if (pix >= 0 && nnix < width && piy >= 0 && nniy < height && piz >= 0 && nniz < depth) {
635 break;
636 }
637
638 /* The Cubic samples span the clip border.
639 * read_clip is used to ensure proper interpolation across the clip border. */
640 const int xc[4] = {pix, ix, nix, nnix};
641 const int yc[4] = {piy, iy, niy, nniy};
642 const int zc[4] = {piz, iz, niz, nniz};
643 return tricubic_lookup(
644 (const TexT *)info.data, tx, ty, tz, xc, yc, zc, width, height, depth, read_clip);
645 }
646 case EXTENSION_EXTEND:
647 pix = wrap_clamp(ix - 1, width);
648 nix = wrap_clamp(ix + 1, width);
649 nnix = wrap_clamp(ix + 2, width);
650 ix = wrap_clamp(ix, width);
651
652 piy = wrap_clamp(iy - 1, height);
653 niy = wrap_clamp(iy + 1, height);
654 nniy = wrap_clamp(iy + 2, height);
655 iy = wrap_clamp(iy, height);
656
657 piz = wrap_clamp(iz - 1, depth);
658 niz = wrap_clamp(iz + 1, depth);
659 nniz = wrap_clamp(iz + 2, depth);
660 iz = wrap_clamp(iz, depth);
661 break;
662 case EXTENSION_MIRROR:
663 pix = wrap_mirror(ix - 1, width);
664 nix = wrap_mirror(ix + 1, width);
665 nnix = wrap_mirror(ix + 2, width);
666 ix = wrap_mirror(ix, width);
667
668 piy = wrap_mirror(iy - 1, height);
669 niy = wrap_mirror(iy + 1, height);
670 nniy = wrap_mirror(iy + 2, height);
671 iy = wrap_mirror(iy, height);
672
673 piz = wrap_mirror(iz - 1, depth);
674 niz = wrap_mirror(iz + 1, depth);
675 nniz = wrap_mirror(iz + 2, depth);
676 iz = wrap_mirror(iz, depth);
677 break;
678 default:
679 kernel_assert(0);
680 return zero();
681 }
682 const int xc[4] = {pix, ix, nix, nnix};
683 const int yc[4] = {piy, iy, niy, nniy};
684 const int zc[4] = {piz, iz, niz, nniz};
685 const TexT *data = (const TexT *)info.data;
686 return tricubic_lookup(data, tx, ty, tz, xc, yc, zc, width, height, depth, read);
687 }
688
690 const TextureInfo &info, const float x, float y, const float z, InterpolationType interp)
691 {
692 switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
694 return interp_3d_closest(info, x, y, z);
696 return interp_3d_linear(info, x, y, z);
697 default:
698 return interp_3d_cubic(info, x, y, z);
699 }
700 }
701};
702
703#ifdef WITH_NANOVDB
704template<typename TexT, typename OutT> struct NanoVDBInterpolator {
705
706 static ccl_always_inline float read(const float r)
707 {
708 return r;
709 }
710
712 {
713 return make_float4(r.x, r.y, r.z, 1.0f);
714 }
715
716 template<typename Acc>
717 static ccl_always_inline OutT
718 interp_3d_closest(const Acc &acc, const float x, float y, const float z)
719 {
720 const nanovdb::Coord coord((int32_t)floorf(x), (int32_t)floorf(y), (int32_t)floorf(z));
721 return read(acc.getValue(coord));
722 }
723
724 template<typename Acc>
725 static ccl_always_inline OutT
726 interp_3d_linear(const Acc &acc, const float x, float y, const float z)
727 {
728 int ix, iy, iz;
729 const float tx = frac(x - 0.5f, &ix);
730 const float ty = frac(y - 0.5f, &iy);
731 const float tz = frac(z - 0.5f, &iz);
732
733 return mix(mix(mix(read(acc.getValue(nanovdb::Coord(ix, iy, iz))),
734 read(acc.getValue(nanovdb::Coord(ix, iy, iz + 1))),
735 tz),
736 mix(read(acc.getValue(nanovdb::Coord(ix, iy + 1, iz + 1))),
737 read(acc.getValue(nanovdb::Coord(ix, iy + 1, iz))),
738 1.0f - tz),
739 ty),
740 mix(mix(read(acc.getValue(nanovdb::Coord(ix + 1, iy + 1, iz))),
741 read(acc.getValue(nanovdb::Coord(ix + 1, iy + 1, iz + 1))),
742 tz),
743 mix(read(acc.getValue(nanovdb::Coord(ix + 1, iy, iz + 1))),
744 read(acc.getValue(nanovdb::Coord(ix + 1, iy, iz))),
745 1.0f - tz),
746 1.0f - ty),
747 tx);
748 }
749
750 /* Tricubic b-spline interpolation. */
751 template<typename Acc>
752# if defined(__GNUC__) || defined(__clang__)
753 static ccl_always_inline
754# else
755 static ccl_never_inline
756# endif
757 OutT
758 interp_3d_cubic(const Acc &acc, const float x, float y, const float z)
759 {
760 int ix, iy, iz;
761 int nix, niy, niz;
762 int pix, piy, piz;
763 int nnix, nniy, nniz;
764
765 /* A -0.5 offset is used to center the cubic samples around the sample point. */
766 const float tx = frac(x - 0.5f, &ix);
767 const float ty = frac(y - 0.5f, &iy);
768 const float tz = frac(z - 0.5f, &iz);
769
770 pix = ix - 1;
771 piy = iy - 1;
772 piz = iz - 1;
773 nix = ix + 1;
774 niy = iy + 1;
775 niz = iz + 1;
776 nnix = ix + 2;
777 nniy = iy + 2;
778 nniz = iz + 2;
779
780 const int xc[4] = {pix, ix, nix, nnix};
781 const int yc[4] = {piy, iy, niy, nniy};
782 const int zc[4] = {piz, iz, niz, nniz};
783 float u[4], v[4], w[4];
784
785 /* Some helper macros to keep code size reasonable.
786 * Lets the compiler inline all the matrix multiplications.
787 */
788# define DATA(x, y, z) (read(acc.getValue(nanovdb::Coord(xc[x], yc[y], zc[z]))))
789# define COL_TERM(col, row) \
790 (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \
791 u[3] * DATA(3, col, row)))
792# define ROW_TERM(row) \
793 (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
794
798
799 /* Actual interpolation. */
800 return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
801
802# undef COL_TERM
803# undef ROW_TERM
804# undef DATA
805 }
806
807 static ccl_always_inline OutT interp_3d(
808 const TextureInfo &info, const float x, float y, const float z, InterpolationType interp)
809 {
810 using namespace nanovdb;
811
812 NanoGrid<TexT> *const grid = (NanoGrid<TexT> *)info.data;
813
814 switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
816 ReadAccessor<TexT> acc(grid->tree().root());
817 return interp_3d_closest(acc, x, y, z);
818 }
820 CachedReadAccessor<TexT> acc(grid->tree().root());
821 return interp_3d_linear(acc, x, y, z);
822 }
823 default: {
824 CachedReadAccessor<TexT> acc(grid->tree().root());
825 return interp_3d_cubic(acc, x, y, z);
826 }
827 }
828 }
829};
830#endif
831
832#undef SET_CUBIC_SPLINE_WEIGHTS
833
834ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, const int id, const float x, float y)
835{
836 const TextureInfo &info = kernel_data_fetch(texture_info, id);
837
838 if (UNLIKELY(!info.data)) {
839 return zero_float4();
840 }
841
842 switch (info.data_type) {
844 const float f = TextureInterpolator<half, float>::interp(info, x, y);
845 return make_float4(f, f, f, 1.0f);
846 }
848 const float f = TextureInterpolator<uchar, float>::interp(info, x, y);
849 return make_float4(f, f, f, 1.0f);
850 }
852 const float f = TextureInterpolator<uint16_t, float>::interp(info, x, y);
853 return make_float4(f, f, f, 1.0f);
854 }
856 const float f = TextureInterpolator<float, float>::interp(info, x, y);
857 return make_float4(f, f, f, 1.0f);
858 }
867 default:
868 assert(0);
869 return make_float4(
871 }
872}
873
875 const int id,
876 float3 P,
878{
879 const TextureInfo &info = kernel_data_fetch(texture_info, id);
880
881 if (UNLIKELY(!info.data)) {
882 return zero_float4();
883 }
884
885 if (info.use_transform_3d) {
887 }
888 switch (info.data_type) {
890 const float f = TextureInterpolator<half, float>::interp_3d(info, P.x, P.y, P.z, interp);
891 return make_float4(f, f, f, 1.0f);
892 }
894 const float f = TextureInterpolator<uchar, float>::interp_3d(info, P.x, P.y, P.z, interp);
895 return make_float4(f, f, f, 1.0f);
896 }
898 const float f = TextureInterpolator<uint16_t, float>::interp_3d(info, P.x, P.y, P.z, interp);
899 return make_float4(f, f, f, 1.0f);
900 }
902 const float f = TextureInterpolator<float, float>::interp_3d(info, P.x, P.y, P.z, interp);
903 return make_float4(f, f, f, 1.0f);
904 }
906 return TextureInterpolator<half4>::interp_3d(info, P.x, P.y, P.z, interp);
908 return TextureInterpolator<uchar4>::interp_3d(info, P.x, P.y, P.z, interp);
910 return TextureInterpolator<ushort4>::interp_3d(info, P.x, P.y, P.z, interp);
912 return TextureInterpolator<float4>::interp_3d(info, P.x, P.y, P.z, interp);
913#ifdef WITH_NANOVDB
915 const float f = NanoVDBInterpolator<float, float>::interp_3d(info, P.x, P.y, P.z, interp);
916 return make_float4(f, f, f, 1.0f);
917 }
919 return NanoVDBInterpolator<packed_float3, float4>::interp_3d(info, P.x, P.y, P.z, interp);
921 const float f = NanoVDBInterpolator<nanovdb::FpN, float>::interp_3d(
922 info, P.x, P.y, P.z, interp);
923 return make_float4(f, f, f, 1.0f);
924 }
926 const float f = NanoVDBInterpolator<nanovdb::Fp16, float>::interp_3d(
927 info, P.x, P.y, P.z, interp);
928 return make_float4(f, f, f, 1.0f);
929 }
930#endif
931 default:
932 assert(0);
933 return make_float4(
935 }
936}
937
938} /* Namespace. */
939
unsigned char uchar
#define UNLIKELY(x)
blender::float3 packed_float3
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
Definition half.h:41
#define TERM(col)
#define SET_CUBIC_SPLINE_WEIGHTS(u, t)
#define ROW_TERM(row)
CCL_NAMESPACE_BEGIN ccl_device_inline float frac(const float x, ccl_private int *ix)
ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg, const int id, float3 P, InterpolationType interp)
ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, const int id, const float x, float y)
#define kernel_assert(cond)
#define ccl_never_inline
#define kernel_data_fetch(name, index)
#define ccl_always_inline
#define ccl_device
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define CCL_NAMESPACE_END
ccl_device_forceinline float4 make_float4(const float x, const float y, const float z, const float w)
#define floorf(x)
VecBase< float, 4 > float4
#define assert(assertion)
#define abs
constexpr T clamp(T, U, U) RET
ccl_device_inline float4 half4_to_float4_image(const half4 h)
Definition half.h:112
ccl_device_inline float half_to_float_image(half h)
Definition half.h:98
#define mix(a, b, c)
Definition hash.h:35
ccl_device_inline int float_to_int(const float f)
Definition math_base.h:407
ccl_device_inline float interp(const float a, const float b, const float t)
Definition math_base.h:502
CCL_NAMESPACE_BEGIN ccl_device_inline float4 zero_float4()
Definition math_float4.h:13
static ccl_always_inline OutT interp(const TextureInfo &info, const float x, float y)
static ccl_never_inline OutT interp_3d_cubic(const TextureInfo &info, const float x, float y, const float z)
static ccl_always_inline float read(const uint16_t r)
static ccl_always_inline int wrap_mirror(const int x, const int width)
static ccl_always_inline OutT tricubic_lookup(const TexT *data, const float tx, const float ty, const float tz, const int xc[4], const int yc[4], const int zc[4], const int width, const int height, const int depth, OutT read(const TexT *, int, int, int, int, int, int))
static ccl_always_inline OutT read(const TexT *data, const int x, int y, const int width, const int height)
static ccl_always_inline OutT read_clip(const TexT *data, const int x, int y, const int z, int width, const int height, const int depth)
static ccl_always_inline OutT interp_3d(const TextureInfo &info, const float x, float y, const float z, InterpolationType interp)
static ccl_always_inline float4 read(const uchar4 r)
static ccl_always_inline OutT interp_3d_linear(const TextureInfo &info, const float x, const float y, const float z)
static ccl_always_inline OutT trilinear_lookup(const TexT *data, const float tx, const float ty, const float tz, const int ix, const int iy, const int iz, const int nix, const int niy, const int niz, const int width, const int height, const int depth, OutT read(const TexT *, int, int, int, int, int, int))
static ccl_always_inline float read(const uchar r)
static ccl_always_inline OutT interp_linear(const TextureInfo &info, const float x, float y)
static ccl_always_inline OutT interp_cubic(const TextureInfo &info, const float x, float y)
static ccl_always_inline OutT interp_closest(const TextureInfo &info, const float x, float y)
static ccl_always_inline int wrap_periodic(int x, const int width)
static ccl_always_inline OutT interp_3d_closest(const TextureInfo &info, const float x, const float y, const float z)
static ccl_always_inline float4 read(const float4 r)
static ccl_always_inline float4 read(ushort4 r)
static ccl_always_inline OutT read_clip(const TexT *data, const int x, int y, const int width, const int height)
static ccl_always_inline float4 read(half4 r)
static ccl_always_inline int wrap_clamp(const int x, const int width)
static ccl_always_inline float read(const float r)
static ccl_always_inline float read(half r)
static ccl_always_inline OutT read(const TexT *data, const int x, int y, const int z, int width, const int height, const int depth)
uint64_t data
uint use_transform_3d
uint interpolation
Transform transform_3d
Definition half.h:60
uchar z
uchar w
uchar x
uchar y
uint16_t w
uint16_t y
uint16_t z
uint16_t x
read
i
Definition text_draw.cc:230
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56
@ IMAGE_DATA_TYPE_BYTE
@ IMAGE_DATA_TYPE_FLOAT
@ IMAGE_DATA_TYPE_NANOVDB_FP16
@ IMAGE_DATA_TYPE_FLOAT4
@ IMAGE_DATA_TYPE_USHORT4
@ IMAGE_DATA_TYPE_USHORT
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT3
@ IMAGE_DATA_TYPE_HALF
@ IMAGE_DATA_TYPE_BYTE4
@ IMAGE_DATA_TYPE_HALF4
@ IMAGE_DATA_TYPE_NANOVDB_FPN
InterpolationType
@ INTERPOLATION_LINEAR
@ INTERPOLATION_NONE
@ INTERPOLATION_CLOSEST
@ TEX_IMAGE_MISSING_G
@ TEX_IMAGE_MISSING_A
@ TEX_IMAGE_MISSING_R
@ TEX_IMAGE_MISSING_B
@ EXTENSION_REPEAT
@ EXTENSION_CLIP
@ EXTENSION_EXTEND
@ EXTENSION_MIRROR