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