Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/device/cpu/image.h
| Show All 9 Lines | |||||
| #endif | #endif | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| /* Make template functions private so symbols don't conflict between kernels with different | /* Make template functions private so symbols don't conflict between kernels with different | ||||
| * instruction sets. */ | * instruction sets. */ | ||||
| namespace { | namespace { | ||||
| #define ERROR_COLOR make_float4(0.0f, 0.0f, 0.0f, 0.0f) | |||||
| #define SET_CUBIC_SPLINE_WEIGHTS(u, t) \ | #define SET_CUBIC_SPLINE_WEIGHTS(u, t) \ | ||||
| { \ | { \ | ||||
| u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \ | u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \ | ||||
| u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \ | u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \ | ||||
| u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \ | u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \ | ||||
| u[3] = (1.0f / 6.0f) * t * t * t; \ | u[3] = (1.0f / 6.0f) * t * t * t; \ | ||||
| } \ | } \ | ||||
| (void)0 | (void)0 | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | template<typename T> struct TextureInterpolator { | ||||
| static ccl_always_inline float4 read(const T *data, int x, int y, int width, int height) | static ccl_always_inline float4 read(const T *data, int x, int y, int width, int height) | ||||
| { | { | ||||
| if (x < 0 || y < 0 || x >= width || y >= height) { | if (x < 0 || y < 0 || x >= width || y >= height) { | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | ||||
| } | } | ||||
| return read(data[y * width + x]); | return read(data[y * width + x]); | ||||
| } | } | ||||
| static ccl_always_inline float4 | |||||
| read(const T *data, int x, int y, int z, int width, int height, int depth) | |||||
| { | |||||
| if (x < 0 || y < 0 || z < 0 || x >= width || y >= height || z >= depth) { | |||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | |||||
| } | |||||
| return read(data[x + y * width + z * width * height]); | |||||
| } | |||||
| static ccl_always_inline int wrap_periodic(int x, int width) | static ccl_always_inline int wrap_periodic(int x, int width) | ||||
| { | { | ||||
| x %= width; | x %= width; | ||||
| if (x < 0) | if (x < 0) { | ||||
| x += width; | x += width; | ||||
| } | |||||
| return x; | return x; | ||||
| } | } | ||||
| static ccl_always_inline int wrap_clamp(int x, int width) | static ccl_always_inline int wrap_clamp(int x, int width) | ||||
| { | { | ||||
| return clamp(x, 0, width - 1); | return clamp(x, 0, width - 1); | ||||
| } | } | ||||
| /* ******** 2D interpolation ******** */ | /* ******** 2D interpolation ******** */ | ||||
| static ccl_always_inline float4 interp_closest(const TextureInfo &info, float x, float y) | static ccl_always_inline float4 interp_closest(const TextureInfo &info, float x, float y) | ||||
| { | { | ||||
| const T *data = (const T *)info.data; | const T *data = (const T *)info.data; | ||||
| const int width = info.width; | const int width = info.width; | ||||
| const int height = info.height; | const int height = info.height; | ||||
| int ix, iy; | int ix, iy; | ||||
| frac(x * (float)width, &ix); | frac(x * (float)width, &ix); | ||||
| frac(y * (float)height, &iy); | frac(y * (float)height, &iy); | ||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | ix = wrap_periodic(ix, width); | ||||
| iy = wrap_periodic(iy, height); | iy = wrap_periodic(iy, height); | ||||
| break; | break; | ||||
| case EXTENSION_CLIP: | case EXTENSION_CLIP: | ||||
| if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { | if (x < 0.0f || x > 1.0f || y < 0.0f || y > 1.0f) { | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | ||||
| } | } | ||||
| ATTR_FALLTHROUGH; | break; | ||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| ix = wrap_clamp(ix, width); | ix = wrap_clamp(ix, width); | ||||
| iy = wrap_clamp(iy, height); | iy = wrap_clamp(iy, height); | ||||
| break; | break; | ||||
| default: | default: | ||||
| kernel_assert(0); | kernel_assert(0); | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return ERROR_COLOR; | ||||
| } | } | ||||
| return read(data[ix + iy * width]); | return read(data[ix + iy * width]); | ||||
| } | } | ||||
| static ccl_always_inline float4 interp_linear(const TextureInfo &info, float x, float y) | static ccl_always_inline float4 interp_linear(const TextureInfo &info, float x, float y) | ||||
| { | { | ||||
| const T *data = (const T *)info.data; | const T *data = (const T *)info.data; | ||||
| const int width = info.width; | const int width = info.width; | ||||
| const int height = info.height; | const int height = info.height; | ||||
| int ix, iy, nix, niy; | int ix, iy, nix, niy; | ||||
| const float tx = frac(x * (float)width - 0.5f, &ix); | const float tx = frac(x * (float)width - 0.5f, &ix); | ||||
| const float ty = frac(y * (float)height - 0.5f, &iy); | const float ty = frac(y * (float)height - 0.5f, &iy); | ||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | |||||
| iy = wrap_periodic(iy, height); | |||||
| nix = wrap_periodic(ix + 1, width); | nix = wrap_periodic(ix + 1, width); | ||||
| ix = wrap_periodic(ix, width); | |||||
| niy = wrap_periodic(iy + 1, height); | niy = wrap_periodic(iy + 1, height); | ||||
| iy = wrap_periodic(iy, height); | |||||
| break; | break; | ||||
| case EXTENSION_CLIP: | case EXTENSION_CLIP: | ||||
| nix = ix + 1; | nix = ix + 1; | ||||
| niy = iy + 1; | niy = iy + 1; | ||||
| break; | break; | ||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| nix = wrap_clamp(ix + 1, width); | nix = wrap_clamp(ix + 1, width); | ||||
| niy = wrap_clamp(iy + 1, height); | |||||
| ix = wrap_clamp(ix, width); | ix = wrap_clamp(ix, width); | ||||
| niy = wrap_clamp(iy + 1, height); | |||||
| iy = wrap_clamp(iy, height); | iy = wrap_clamp(iy, height); | ||||
| break; | break; | ||||
| default: | default: | ||||
| kernel_assert(0); | kernel_assert(0); | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return ERROR_COLOR; | ||||
| } | } | ||||
| return (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, width, height) + | return (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, width, height) + | ||||
| (1.0f - ty) * tx * read(data, nix, iy, width, height) + | (1.0f - ty) * tx * read(data, nix, iy, width, height) + | ||||
| ty * (1.0f - tx) * read(data, ix, niy, width, height) + | ty * (1.0f - tx) * read(data, ix, niy, width, height) + | ||||
| ty * tx * read(data, nix, niy, width, height); | ty * tx * read(data, nix, niy, width, height); | ||||
| } | } | ||||
| static ccl_always_inline float4 interp_cubic(const TextureInfo &info, float x, float y) | static ccl_always_inline float4 interp_cubic(const TextureInfo &info, float x, float y) | ||||
| { | { | ||||
| const T *data = (const T *)info.data; | const T *data = (const T *)info.data; | ||||
| const int width = info.width; | const int width = info.width; | ||||
| const int height = info.height; | const int height = info.height; | ||||
| int ix, iy, nix, niy; | int ix, iy, nix, niy; | ||||
| const float tx = frac(x * (float)width - 0.5f, &ix); | const float tx = frac(x * (float)width - 0.5f, &ix); | ||||
| const float ty = frac(y * (float)height - 0.5f, &iy); | const float ty = frac(y * (float)height - 0.5f, &iy); | ||||
| int pix, piy, nnix, nniy; | int pix, piy, nnix, nniy; | ||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | |||||
| iy = wrap_periodic(iy, height); | |||||
| pix = wrap_periodic(ix - 1, width); | pix = wrap_periodic(ix - 1, width); | ||||
| piy = wrap_periodic(iy - 1, height); | |||||
| nix = wrap_periodic(ix + 1, width); | nix = wrap_periodic(ix + 1, width); | ||||
| niy = wrap_periodic(iy + 1, height); | |||||
| nnix = wrap_periodic(ix + 2, width); | nnix = wrap_periodic(ix + 2, width); | ||||
| ix = wrap_periodic(ix, width); | |||||
| piy = wrap_periodic(iy - 1, height); | |||||
| niy = wrap_periodic(iy + 1, height); | |||||
| nniy = wrap_periodic(iy + 2, height); | nniy = wrap_periodic(iy + 2, height); | ||||
| iy = wrap_periodic(iy, height); | |||||
| break; | break; | ||||
| case EXTENSION_CLIP: | case EXTENSION_CLIP: | ||||
| pix = ix - 1; | pix = ix - 1; | ||||
| piy = iy - 1; | |||||
| nix = ix + 1; | nix = ix + 1; | ||||
| niy = iy + 1; | |||||
| nnix = ix + 2; | nnix = ix + 2; | ||||
| piy = iy - 1; | |||||
| niy = iy + 1; | |||||
| nniy = iy + 2; | nniy = iy + 2; | ||||
| break; | break; | ||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| pix = wrap_clamp(ix - 1, width); | pix = wrap_clamp(ix - 1, width); | ||||
| piy = wrap_clamp(iy - 1, height); | |||||
| nix = wrap_clamp(ix + 1, width); | nix = wrap_clamp(ix + 1, width); | ||||
| niy = wrap_clamp(iy + 1, height); | |||||
| nnix = wrap_clamp(ix + 2, width); | nnix = wrap_clamp(ix + 2, width); | ||||
| nniy = wrap_clamp(iy + 2, height); | |||||
| ix = wrap_clamp(ix, width); | ix = wrap_clamp(ix, width); | ||||
| piy = wrap_clamp(iy - 1, height); | |||||
| niy = wrap_clamp(iy + 1, height); | |||||
| nniy = wrap_clamp(iy + 2, height); | |||||
| iy = wrap_clamp(iy, height); | iy = wrap_clamp(iy, height); | ||||
| break; | break; | ||||
| default: | default: | ||||
| kernel_assert(0); | kernel_assert(0); | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return ERROR_COLOR; | ||||
| } | } | ||||
| const int xc[4] = {pix, ix, nix, nnix}; | const int xc[4] = {pix, ix, nix, nnix}; | ||||
| const int yc[4] = {piy, iy, niy, nniy}; | const int yc[4] = {piy, iy, niy, nniy}; | ||||
| float u[4], v[4]; | float u[4], v[4]; | ||||
| /* Some helper macro to keep code reasonable size, | /* Some helper macro to keep code reasonable size, | ||||
| * let compiler to inline all the matrix multiplications. | * let compiler to inline all the matrix multiplications. | ||||
| */ | */ | ||||
| #define DATA(x, y) (read(data, xc[x], yc[y], width, height)) | #define DATA(x, y) (read(data, xc[x], yc[y], width, height)) | ||||
| #define TERM(col) \ | #define TERM(col) \ | ||||
| (v[col] * \ | (v[col] * \ | ||||
| (u[0] * DATA(0, col) + u[1] * DATA(1, col) + u[2] * DATA(2, col) + u[3] * DATA(3, col))) | (u[0] * DATA(0, col) + u[1] * DATA(1, col) + u[2] * DATA(2, col) + u[3] * DATA(3, col))) | ||||
| SET_CUBIC_SPLINE_WEIGHTS(u, tx); | SET_CUBIC_SPLINE_WEIGHTS(u, tx); | ||||
| SET_CUBIC_SPLINE_WEIGHTS(v, ty); | SET_CUBIC_SPLINE_WEIGHTS(v, ty); | ||||
| /* Actual interpolation. */ | /* Actual interpolation. */ | ||||
| return TERM(0) + TERM(1) + TERM(2) + TERM(3); | return TERM(0) + TERM(1) + TERM(2) + TERM(3); | ||||
| #undef TERM | #undef TERM | ||||
| #undef DATA | #undef DATA | ||||
| } | } | ||||
| static ccl_always_inline float4 interp(const TextureInfo &info, float x, float y) | static ccl_always_inline float4 interp(const TextureInfo &info, float x, float y) | ||||
| { | { | ||||
| if (UNLIKELY(!info.data)) { | if (UNLIKELY(!info.data)) { | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return ERROR_COLOR; | ||||
| } | } | ||||
| switch (info.interpolation) { | switch (info.interpolation) { | ||||
| case INTERPOLATION_CLOSEST: | case INTERPOLATION_CLOSEST: | ||||
| return interp_closest(info, x, y); | return interp_closest(info, x, y); | ||||
| case INTERPOLATION_LINEAR: | case INTERPOLATION_LINEAR: | ||||
| return interp_linear(info, x, y); | return interp_linear(info, x, y); | ||||
| default: | default: | ||||
| return interp_cubic(info, x, y); | return interp_cubic(info, x, y); | ||||
| Show All 21 Lines | switch (info.extension) { | ||||
| ix = wrap_periodic(ix, width); | ix = wrap_periodic(ix, width); | ||||
| iy = wrap_periodic(iy, height); | iy = wrap_periodic(iy, height); | ||||
| iz = wrap_periodic(iz, depth); | iz = wrap_periodic(iz, depth); | ||||
| break; | break; | ||||
| case EXTENSION_CLIP: | case EXTENSION_CLIP: | ||||
| if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { | if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | ||||
| } | } | ||||
| ATTR_FALLTHROUGH; | break; | ||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| ix = wrap_clamp(ix, width); | ix = wrap_clamp(ix, width); | ||||
| iy = wrap_clamp(iy, height); | iy = wrap_clamp(iy, height); | ||||
| iz = wrap_clamp(iz, depth); | iz = wrap_clamp(iz, depth); | ||||
| break; | break; | ||||
| default: | default: | ||||
| kernel_assert(0); | kernel_assert(0); | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return ERROR_COLOR; | ||||
| } | } | ||||
| const T *data = (const T *)info.data; | const T *data = (const T *)info.data; | ||||
| return read(data[ix + iy * width + iz * width * height]); | return read(data[ix + iy * width + iz * width * height]); | ||||
| } | } | ||||
| static ccl_always_inline float4 interp_3d_linear(const TextureInfo &info, | static ccl_always_inline float4 interp_3d_linear(const TextureInfo &info, | ||||
| float x, | float x, | ||||
| float y, | float y, | ||||
| float z) | float z) | ||||
| { | { | ||||
| int width = info.width; | int width = info.width; | ||||
| int height = info.height; | int height = info.height; | ||||
| int depth = info.depth; | int depth = info.depth; | ||||
| int ix, iy, iz; | int ix, iy, iz; | ||||
| int nix, niy, niz; | int nix, niy, niz; | ||||
| float tx = frac(x * (float)width - 0.5f, &ix); | float tx = frac(x * (float)width - 0.5f, &ix); | ||||
| float ty = frac(y * (float)height - 0.5f, &iy); | float ty = frac(y * (float)height - 0.5f, &iy); | ||||
| float tz = frac(z * (float)depth - 0.5f, &iz); | float tz = frac(z * (float)depth - 0.5f, &iz); | ||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | |||||
| iy = wrap_periodic(iy, height); | |||||
| iz = wrap_periodic(iz, depth); | |||||
| nix = wrap_periodic(ix + 1, width); | nix = wrap_periodic(ix + 1, width); | ||||
| niy = wrap_periodic(iy + 1, height); | niy = wrap_periodic(iy + 1, height); | ||||
| niz = wrap_periodic(iz + 1, depth); | niz = wrap_periodic(iz + 1, depth); | ||||
| ix = wrap_periodic(ix, width); | |||||
| iy = wrap_periodic(iy, height); | |||||
| iz = wrap_periodic(iz, depth); | |||||
| break; | break; | ||||
| case EXTENSION_CLIP: | case EXTENSION_CLIP: | ||||
| if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { | nix = ix + 1; | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | niy = iy + 1; | ||||
| } | niz = iz + 1; | ||||
| ATTR_FALLTHROUGH; | break; | ||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| nix = wrap_clamp(ix + 1, width); | nix = wrap_clamp(ix + 1, width); | ||||
| niy = wrap_clamp(iy + 1, height); | niy = wrap_clamp(iy + 1, height); | ||||
| niz = wrap_clamp(iz + 1, depth); | niz = wrap_clamp(iz + 1, depth); | ||||
| ix = wrap_clamp(ix, width); | ix = wrap_clamp(ix, width); | ||||
| iy = wrap_clamp(iy, height); | iy = wrap_clamp(iy, height); | ||||
| iz = wrap_clamp(iz, depth); | iz = wrap_clamp(iz, depth); | ||||
| break; | break; | ||||
| default: | default: | ||||
| kernel_assert(0); | kernel_assert(0); | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return ERROR_COLOR; | ||||
| } | } | ||||
| const T *data = (const T *)info.data; | const T *data = (const T *)info.data; | ||||
| float4 r; | float4 r; | ||||
| r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) * | r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, iz, width, height, depth); | ||||
| read(data[ix + iy * width + iz * width * height]); | r += (1.0f - tz) * (1.0f - ty) * tx * read(data, nix, iy, iz, width, height, depth); | ||||
| r += (1.0f - tz) * (1.0f - ty) * tx * read(data[nix + iy * width + iz * width * height]); | r += (1.0f - tz) * ty * (1.0f - tx) * read(data, ix, niy, iz, width, height, depth); | ||||
| r += (1.0f - tz) * ty * (1.0f - tx) * read(data[ix + niy * width + iz * width * height]); | r += (1.0f - tz) * ty * tx * read(data, nix, niy, iz, width, height, depth); | ||||
| r += (1.0f - tz) * ty * tx * read(data[nix + niy * width + iz * width * height]); | |||||
| r += tz * (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, niz, width, height, depth); | |||||
| r += tz * (1.0f - ty) * (1.0f - tx) * read(data[ix + iy * width + niz * width * height]); | r += tz * (1.0f - ty) * tx * read(data, nix, iy, niz, width, height, depth); | ||||
| r += tz * (1.0f - ty) * tx * read(data[nix + iy * width + niz * width * height]); | r += tz * ty * (1.0f - tx) * read(data, ix, niy, niz, width, height, depth); | ||||
| r += tz * ty * (1.0f - tx) * read(data[ix + niy * width + niz * width * height]); | r += tz * ty * tx * read(data, nix, niy, niz, width, height, depth); | ||||
| r += tz * ty * tx * read(data[nix + niy * width + niz * width * height]); | |||||
| return r; | return r; | ||||
| } | } | ||||
| /* TODO(sergey): For some unspeakable reason both GCC-6 and Clang-3.9 are | /* TODO(sergey): For some unspeakable reason both GCC-6 and Clang-3.9 are | ||||
| * causing stack overflow issue in this function unless it is inlined. | * causing stack overflow issue in this function unless it is inlined. | ||||
| * | * | ||||
| * Only happens for AVX2 kernel and global __KERNEL_SSE__ vectorization | * Only happens for AVX2 kernel and global __KERNEL_SSE__ vectorization | ||||
| Show All 15 Lines | #endif | ||||
| /* Tricubic b-spline interpolation. */ | /* Tricubic b-spline interpolation. */ | ||||
| const float tx = frac(x * (float)width - 0.5f, &ix); | const float tx = frac(x * (float)width - 0.5f, &ix); | ||||
| const float ty = frac(y * (float)height - 0.5f, &iy); | const float ty = frac(y * (float)height - 0.5f, &iy); | ||||
| const float tz = frac(z * (float)depth - 0.5f, &iz); | const float tz = frac(z * (float)depth - 0.5f, &iz); | ||||
| int pix, piy, piz, nnix, nniy, nniz; | int pix, piy, piz, nnix, nniy, nniz; | ||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | |||||
| iy = wrap_periodic(iy, height); | |||||
| iz = wrap_periodic(iz, depth); | |||||
| pix = wrap_periodic(ix - 1, width); | pix = wrap_periodic(ix - 1, width); | ||||
| piy = wrap_periodic(iy - 1, height); | piy = wrap_periodic(iy - 1, height); | ||||
| piz = wrap_periodic(iz - 1, depth); | piz = wrap_periodic(iz - 1, depth); | ||||
| nix = wrap_periodic(ix + 1, width); | nix = wrap_periodic(ix + 1, width); | ||||
| niy = wrap_periodic(iy + 1, height); | niy = wrap_periodic(iy + 1, height); | ||||
| niz = wrap_periodic(iz + 1, depth); | niz = wrap_periodic(iz + 1, depth); | ||||
| nnix = wrap_periodic(ix + 2, width); | nnix = wrap_periodic(ix + 2, width); | ||||
| nniy = wrap_periodic(iy + 2, height); | nniy = wrap_periodic(iy + 2, height); | ||||
| nniz = wrap_periodic(iz + 2, depth); | nniz = wrap_periodic(iz + 2, depth); | ||||
| ix = wrap_periodic(ix, width); | |||||
| iy = wrap_periodic(iy, height); | |||||
| iz = wrap_periodic(iz, depth); | |||||
| break; | break; | ||||
| case EXTENSION_CLIP: | case EXTENSION_CLIP: | ||||
| if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { | pix = ix - 1; | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | piy = iy - 1; | ||||
| } | piz = iz - 1; | ||||
| ATTR_FALLTHROUGH; | |||||
| nix = ix + 1; | |||||
| niy = iy + 1; | |||||
| niz = iz + 1; | |||||
| nnix = ix + 2; | |||||
| nniy = iy + 2; | |||||
| nniz = iz + 2; | |||||
| break; | |||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| pix = wrap_clamp(ix - 1, width); | pix = wrap_clamp(ix - 1, width); | ||||
| piy = wrap_clamp(iy - 1, height); | piy = wrap_clamp(iy - 1, height); | ||||
| piz = wrap_clamp(iz - 1, depth); | piz = wrap_clamp(iz - 1, depth); | ||||
| nix = wrap_clamp(ix + 1, width); | nix = wrap_clamp(ix + 1, width); | ||||
| niy = wrap_clamp(iy + 1, height); | niy = wrap_clamp(iy + 1, height); | ||||
| niz = wrap_clamp(iz + 1, depth); | niz = wrap_clamp(iz + 1, depth); | ||||
| nnix = wrap_clamp(ix + 2, width); | nnix = wrap_clamp(ix + 2, width); | ||||
| nniy = wrap_clamp(iy + 2, height); | nniy = wrap_clamp(iy + 2, height); | ||||
| nniz = wrap_clamp(iz + 2, depth); | nniz = wrap_clamp(iz + 2, depth); | ||||
| ix = wrap_clamp(ix, width); | ix = wrap_clamp(ix, width); | ||||
| iy = wrap_clamp(iy, height); | iy = wrap_clamp(iy, height); | ||||
| iz = wrap_clamp(iz, depth); | iz = wrap_clamp(iz, depth); | ||||
| break; | break; | ||||
| default: | default: | ||||
| kernel_assert(0); | kernel_assert(0); | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return ERROR_COLOR; | ||||
| } | } | ||||
| const int xc[4] = {pix, ix, nix, nnix}; | const int xc[4] = {pix, ix, nix, nnix}; | ||||
| const int yc[4] = {width * piy, width * iy, width * niy, width * nniy}; | const int yc[4] = {piy, iy, niy, nniy}; | ||||
| const int zc[4] = { | const int zc[4] = {piz, iz, niz, nniz}; | ||||
| width * height * piz, width * height * iz, width * height * niz, width * height * nniz}; | |||||
| float u[4], v[4], w[4]; | float u[4], v[4], w[4]; | ||||
| /* Some helper macro to keep code reasonable size, | /* Some helper macro to keep code reasonable size, | ||||
| * let compiler to inline all the matrix multiplications. | * let compiler to inline all the matrix multiplications. | ||||
| */ | */ | ||||
| #define DATA(x, y, z) (read(data[xc[x] + yc[y] + zc[z]])) | #define DATA(x, y, z) (read(data, xc[x], yc[y], zc[z], width, height, depth)) | ||||
| #define COL_TERM(col, row) \ | #define COL_TERM(col, row) \ | ||||
| (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \ | (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \ | ||||
| u[3] * DATA(3, col, row))) | u[3] * DATA(3, col, row))) | ||||
| #define ROW_TERM(row) \ | #define ROW_TERM(row) \ | ||||
| (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row))) | (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row))) | ||||
| SET_CUBIC_SPLINE_WEIGHTS(u, tx); | SET_CUBIC_SPLINE_WEIGHTS(u, tx); | ||||
| SET_CUBIC_SPLINE_WEIGHTS(v, ty); | SET_CUBIC_SPLINE_WEIGHTS(v, ty); | ||||
| SET_CUBIC_SPLINE_WEIGHTS(w, tz); | SET_CUBIC_SPLINE_WEIGHTS(w, tz); | ||||
| /* Actual interpolation. */ | /* Actual interpolation. */ | ||||
| const T *data = (const T *)info.data; | const T *data = (const T *)info.data; | ||||
| return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3); | return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3); | ||||
| #undef COL_TERM | #undef COL_TERM | ||||
| #undef ROW_TERM | #undef ROW_TERM | ||||
| #undef DATA | #undef DATA | ||||
| } | } | ||||
| static ccl_always_inline float4 | static ccl_always_inline float4 | ||||
| interp_3d(const TextureInfo &info, float x, float y, float z, InterpolationType interp) | interp_3d(const TextureInfo &info, float x, float y, float z, InterpolationType interp) | ||||
| { | { | ||||
| if (UNLIKELY(!info.data)) | if (UNLIKELY(!info.data)) | ||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return ERROR_COLOR; | ||||
| switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) { | switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) { | ||||
| case INTERPOLATION_CLOSEST: | case INTERPOLATION_CLOSEST: | ||||
| return interp_3d_closest(info, x, y, z); | return interp_3d_closest(info, x, y, z); | ||||
| case INTERPOLATION_LINEAR: | case INTERPOLATION_LINEAR: | ||||
| return interp_3d_linear(info, x, y, z); | return interp_3d_linear(info, x, y, z); | ||||
| default: | default: | ||||
| return interp_3d_cubic(info, x, y, z); | return interp_3d_cubic(info, x, y, z); | ||||
| ▲ Show 20 Lines • Show All 184 Lines • Show Last 20 Lines | |||||