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 49 Lines • ▼ Show 20 Lines | template<typename T> struct TextureInterpolator { | ||||
| } | } | ||||
| static ccl_always_inline float4 read(ushort4 r) | static ccl_always_inline float4 read(ushort4 r) | ||||
| { | { | ||||
| float f = 1.0f / 65535.0f; | float f = 1.0f / 65535.0f; | ||||
| return make_float4(r.x * f, r.y * f, r.z * f, r.w * f); | return make_float4(r.x * f, r.y * f, r.z * f, r.w * f); | ||||
| } | } | ||||
| /** Read 2D Texture Data | |||||
| * -Does not check if data request is in bounds. | |||||
| */ | |||||
| 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) { | return read(data[y * width + x]); | ||||
| } | |||||
| /** Read 2D Texture Data Clip | |||||
| * -Returns transparent black if data request is out of bounds. | |||||
| */ | |||||
| static ccl_always_inline float4 read_clip(const T *data, int x, int y, int width, int height) | |||||
| { | |||||
| if (x < 0 || x >= width || y < 0 || 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]); | ||||
| } | } | ||||
| /** Read 3D Texture Data | |||||
| * -Does not check if data request is in bounds. | |||||
| */ | |||||
| static ccl_always_inline float4 | |||||
| read(const T *data, int x, int y, int z, int width, int height, int depth) | |||||
| { | |||||
| return read(data[x + y * width + z * width * height]); | |||||
| } | |||||
| /** Read 3D Texture Data Clip | |||||
| * -Returns transparent black if data request is out of bounds. | |||||
| */ | |||||
| static ccl_always_inline float4 | |||||
| read_clip(const T *data, int x, int y, int z, int width, int height, int depth) | |||||
| { | |||||
| if (x < 0 || x >= width || y < 0 || y >= height || z < 0 || z >= depth) { | |||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | |||||
| } | |||||
| return read(data[x + y * width + z * width * height]); | |||||
| } | |||||
| typedef float4 (*ReadType3DTexture)(const T *, int, int, int, int, int, int); | |||||
| /* Trilinear Interpolation */ | |||||
| static ccl_always_inline float4 | |||||
| trilenear_lookup(const T *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, | |||||
| float4 read(const T *, int, int, int, int, int, int)) | |||||
| { | |||||
| float4 r; | |||||
| r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, iz, width, height, depth); | |||||
| r += (1.0f - tz) * (1.0f - ty) * tx * read(data, nix, iy, iz, width, height, depth); | |||||
| r += (1.0f - tz) * ty * (1.0f - tx) * read(data, ix, niy, iz, width, height, depth); | |||||
| r += (1.0f - tz) * ty * tx * read(data, nix, niy, iz, width, height, depth); | |||||
| r += tz * (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, niz, width, height, depth); | |||||
| r += tz * (1.0f - ty) * tx * read(data, nix, iy, niz, width, height, depth); | |||||
| r += tz * ty * (1.0f - tx) * read(data, ix, niy, niz, width, height, depth); | |||||
| r += tz * ty * tx * read(data, nix, niy, niz, width, height, depth); | |||||
| return r; | |||||
| } | |||||
| /** Tricubic Interpolation */ | |||||
| static ccl_always_inline float4 | |||||
| tricubic_lookup(const T *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, | |||||
| float4 read(const T *, int, int, int, int, int, int)) | |||||
| { | |||||
| float u[4], v[4], w[4]; | |||||
| /* Some helper macros to keep code size reasonable. | |||||
| * Lets the compiler inline all the matrix multiplications. | |||||
| */ | |||||
| #define DATA(x, y, z) (read(data, xc[x], yc[y], zc[z], width, height, depth)) | |||||
| #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) + \ | |||||
| u[3] * DATA(3, col, row))) | |||||
| #define ROW_TERM(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(v, ty); | |||||
| SET_CUBIC_SPLINE_WEIGHTS(w, tz); | |||||
| /* Actual interpolation. */ | |||||
| return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3); | |||||
| #undef COL_TERM | |||||
| #undef ROW_TERM | |||||
| #undef DATA | |||||
| } | |||||
| 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 int width = info.width; | |||||
| const int height = info.height; | |||||
| int ix, iy; | int ix, iy; | ||||
| frac(x * (float)width, &ix); | |||||
| frac(y * (float)height, &iy); | frac(x * (float)info.width, &ix); | ||||
| frac(y * (float)info.height, &iy); | |||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | ix = wrap_periodic(ix, info.width); | ||||
| iy = wrap_periodic(iy, height); | iy = wrap_periodic(iy, info.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, info.width); | ||||
| iy = wrap_clamp(iy, height); | iy = wrap_clamp(iy, info.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]); | const T *data = (const T *)info.data; | ||||
| return read(data[ix + iy * info.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; | int ix, iy; | ||||
| const int width = info.width; | int nix, niy; | ||||
| const int height = info.height; | |||||
| int ix, iy, nix, niy; | /* A -0.5 offset is used to center the linear samples around the sample point. */ | ||||
| const float tx = frac(x * (float)width - 0.5f, &ix); | const float tx = frac(x * (float)info.width - 0.5f, &ix); | ||||
| const float ty = frac(y * (float)height - 0.5f, &iy); | const float ty = frac(y * (float)info.height - 0.5f, &iy); | ||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | ix = wrap_periodic(ix, info.width); | ||||
| iy = wrap_periodic(iy, height); | nix = wrap_periodic(ix + 1, info.width); | ||||
| nix = wrap_periodic(ix + 1, width); | |||||
| niy = wrap_periodic(iy + 1, height); | iy = wrap_periodic(iy, info.height); | ||||
| niy = wrap_periodic(iy + 1, info.height); | |||||
| break; | break; | ||||
| case EXTENSION_CLIP: | case EXTENSION_CLIP: | ||||
| if (ix < -1 || ix >= info.width || iy < -1 || iy >= info.height) { | |||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | |||||
| } | |||||
| 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 = ix + 1; | ||||
| niy = wrap_clamp(iy + 1, height); | if (ix < 0) { | ||||
| ix = wrap_clamp(ix, width); | ix = 0; | ||||
| iy = wrap_clamp(iy, height); | nix = 0; | ||||
| } | |||||
| else if (nix >= info.width) { | |||||
| ix = info.width - 1; | |||||
| nix = info.width - 1; | |||||
| } | |||||
| niy = iy + 1; | |||||
| if (iy < 0) { | |||||
| iy = 0; | |||||
| niy = 0; | |||||
| } | |||||
| else if (niy >= info.height) { | |||||
| iy = info.height - 1; | |||||
| niy = info.height - 1; | |||||
| } | |||||
| 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) + | const T *data = (const T *)info.data; | ||||
| (1.0f - ty) * tx * read(data, nix, iy, width, height) + | return (1.0f - ty) * (1.0f - tx) * read_clip(data, ix, iy, info.width, info.height) + | ||||
| ty * (1.0f - tx) * read(data, ix, niy, width, height) + | (1.0f - ty) * tx * read_clip(data, nix, iy, info.width, info.height) + | ||||
| ty * tx * read(data, nix, niy, width, height); | ty * (1.0f - tx) * read_clip(data, ix, niy, info.width, info.height) + | ||||
| ty * tx * read_clip(data, nix, niy, info.width, info.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; | int pix, piy; | ||||
| const int width = info.width; | int ix, iy; | ||||
| const int height = info.height; | int nix, niy; | ||||
| int ix, iy, nix, niy; | int nnix, nniy; | ||||
| const float tx = frac(x * (float)width - 0.5f, &ix); | |||||
| const float ty = frac(y * (float)height - 0.5f, &iy); | /* A -0.5 offset is used to center the cubic samples around the sample point. */ | ||||
| int pix, piy, nnix, nniy; | const float tx = frac(x * (float)info.width - 0.5f, &ix); | ||||
| const float ty = frac(y * (float)info.height - 0.5f, &iy); | |||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | ix = wrap_periodic(ix, info.width); | ||||
| iy = wrap_periodic(iy, height); | pix = wrap_periodic(ix - 1, info.width); | ||||
| pix = wrap_periodic(ix - 1, width); | nix = wrap_periodic(ix + 1, info.width); | ||||
| piy = wrap_periodic(iy - 1, height); | nnix = wrap_periodic(ix + 2, info.width); | ||||
| nix = wrap_periodic(ix + 1, width); | |||||
| niy = wrap_periodic(iy + 1, height); | iy = wrap_periodic(iy, info.height); | ||||
| nnix = wrap_periodic(ix + 2, width); | piy = wrap_periodic(iy - 1, info.height); | ||||
| nniy = wrap_periodic(iy + 2, height); | niy = wrap_periodic(iy + 1, info.height); | ||||
| nniy = wrap_periodic(iy + 2, info.height); | |||||
| break; | break; | ||||
| case EXTENSION_CLIP: | case EXTENSION_CLIP: { | ||||
| if (ix < -2 || ix > info.width || iy < -2 || iy > info.height) { | |||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | |||||
| } | |||||
| 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; | } | ||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| pix = wrap_clamp(ix - 1, width); | pix = wrap_clamp(ix - 1, info.width); | ||||
| piy = wrap_clamp(iy - 1, height); | nix = wrap_clamp(ix + 1, info.width); | ||||
| nix = wrap_clamp(ix + 1, width); | nnix = wrap_clamp(ix + 2, info.width); | ||||
| niy = wrap_clamp(iy + 1, height); | ix = wrap_clamp(ix, info.width); | ||||
| nnix = wrap_clamp(ix + 2, width); | |||||
| nniy = wrap_clamp(iy + 2, height); | piy = wrap_clamp(iy - 1, info.height); | ||||
| ix = wrap_clamp(ix, width); | niy = wrap_clamp(iy + 1, info.height); | ||||
| iy = wrap_clamp(iy, height); | nniy = wrap_clamp(iy + 2, info.height); | ||||
| iy = wrap_clamp(iy, info.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 T *data = (const T *)info.data; | |||||
| 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, | |||||
| * let compiler to inline all the matrix multiplications. | /* Some helper macros to keep code size reasonable. | ||||
| * Lets the compiler inline all the matrix multiplications. | |||||
| */ | */ | ||||
| #define DATA(x, y) (read(data, xc[x], yc[y], width, height)) | #define DATA(x, y) (read_clip(data, xc[x], yc[y], info.width, info.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); | ||||
| } | } | ||||
| } | } | ||||
| /* ******** 3D interpolation ******** */ | /* ******** 3D interpolation ******** */ | ||||
| static ccl_always_inline float4 interp_3d_closest(const TextureInfo &info, | static ccl_always_inline float4 interp_3d_closest(const TextureInfo &info, | ||||
| float x, | float x, | ||||
| float y, | float y, | ||||
| float z) | float z) | ||||
| { | { | ||||
| int width = info.width; | |||||
| int height = info.height; | |||||
| int depth = info.depth; | |||||
| int ix, iy, iz; | int ix, iy, iz; | ||||
| frac(x * (float)width, &ix); | frac(x * (float)info.width, &ix); | ||||
| frac(y * (float)height, &iy); | frac(y * (float)info.height, &iy); | ||||
| frac(z * (float)depth, &iz); | frac(z * (float)info.depth, &iz); | ||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | ix = wrap_periodic(ix, info.width); | ||||
| iy = wrap_periodic(iy, height); | iy = wrap_periodic(iy, info.height); | ||||
| iz = wrap_periodic(iz, depth); | iz = wrap_periodic(iz, info.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 || x >= 1.0f || y < 0.0f || y >= 1.0f || z < 0.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, info.width); | ||||
| iy = wrap_clamp(iy, height); | iy = wrap_clamp(iy, info.height); | ||||
| iz = wrap_clamp(iz, depth); | iz = wrap_clamp(iz, info.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; | return read((const T *)info.data, ix, iy, iz, info.width, info.height, info.depth); | ||||
| 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 height = info.height; | |||||
| 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); | /* A -0.5 offset is used to center the linear samples around the sample point. */ | ||||
| float ty = frac(y * (float)height - 0.5f, &iy); | float tx = frac(x * (float)info.width - 0.5f, &ix); | ||||
| float tz = frac(z * (float)depth - 0.5f, &iz); | float ty = frac(y * (float)info.height - 0.5f, &iy); | ||||
| float tz = frac(z * (float)info.depth - 0.5f, &iz); | |||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | ix = wrap_periodic(ix, info.width); | ||||
| iy = wrap_periodic(iy, height); | nix = wrap_periodic(ix + 1, info.width); | ||||
| iz = wrap_periodic(iz, depth); | |||||
| iy = wrap_periodic(iy, info.height); | |||||
| nix = wrap_periodic(ix + 1, width); | niy = wrap_periodic(iy + 1, info.height); | ||||
| niy = wrap_periodic(iy + 1, height); | |||||
| niz = wrap_periodic(iz + 1, depth); | iz = wrap_periodic(iz, info.depth); | ||||
| niz = wrap_periodic(iz + 1, info.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) { | /* Case - No linear samples are inside the clip region. */ | ||||
| if (ix < -1 || ix >= info.width || iy < -1 || iy >= info.height || iz < -1 || | |||||
| iz >= info.depth) { | |||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | ||||
| } | } | ||||
| ATTR_FALLTHROUGH; | |||||
| nix = ix + 1; | |||||
| niy = iy + 1; | |||||
| niz = iz + 1; | |||||
| /* Case - All linear samples are inside the clip region. */ | |||||
| if (ix >= 0 && nix < info.width && iy >= 0 && niy < info.height && iz >= 0 && | |||||
| niz < info.depth) { | |||||
| break; | |||||
| } | |||||
| /* Case - The linear samples span the clip border. | |||||
| * #read_clip is used to ensure proper interpolation across the clip border. */ | |||||
| return trilenear_lookup((const T *)info.data, | |||||
| tx, | |||||
| ty, | |||||
| tz, | |||||
| ix, | |||||
| iy, | |||||
| iz, | |||||
| nix, | |||||
| niy, | |||||
| niz, | |||||
| info.width, | |||||
| info.height, | |||||
| info.depth, | |||||
| (ReadType3DTexture)&read_clip); | |||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| nix = wrap_clamp(ix + 1, width); | nix = ix + 1; | ||||
| niy = wrap_clamp(iy + 1, height); | if (ix < 0) { | ||||
| niz = wrap_clamp(iz + 1, depth); | ix = 0; | ||||
| nix = 0; | |||||
| ix = wrap_clamp(ix, width); | } | ||||
| iy = wrap_clamp(iy, height); | else if (nix >= info.width) { | ||||
| iz = wrap_clamp(iz, depth); | ix = info.width - 1; | ||||
| nix = info.width - 1; | |||||
| } | |||||
| niy = iy + 1; | |||||
| if (iy < 0) { | |||||
| iy = 0; | |||||
| niy = 0; | |||||
| } | |||||
| else if (niy >= info.height) { | |||||
| iy = info.height - 1; | |||||
| niy = info.height - 1; | |||||
| } | |||||
| niz = iz + 1; | |||||
| if (iz < 0) { | |||||
| iz = 0; | |||||
| niz = iz; | |||||
| } | |||||
| else if (niz >= info.depth) { | |||||
| iz = info.depth - 1; | |||||
| niz = info.depth - 1; | |||||
| } | |||||
| 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; | return trilenear_lookup((const T *)info.data, | ||||
| float4 r; | tx, | ||||
| ty, | |||||
| r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) * | tz, | ||||
| read(data[ix + iy * width + iz * width * height]); | ix, | ||||
| r += (1.0f - tz) * (1.0f - ty) * tx * read(data[nix + iy * width + iz * width * height]); | iy, | ||||
| r += (1.0f - tz) * ty * (1.0f - tx) * read(data[ix + niy * width + iz * width * height]); | iz, | ||||
| r += (1.0f - tz) * ty * tx * read(data[nix + niy * width + iz * width * height]); | nix, | ||||
| niy, | |||||
| r += tz * (1.0f - ty) * (1.0f - tx) * read(data[ix + iy * width + niz * width * height]); | niz, | ||||
| r += tz * (1.0f - ty) * tx * read(data[nix + iy * width + niz * width * height]); | info.width, | ||||
| r += tz * ty * (1.0f - tx) * read(data[ix + niy * width + niz * width * height]); | info.height, | ||||
| r += tz * ty * tx * read(data[nix + niy * width + niz * width * height]); | info.depth, | ||||
| (ReadType3DTexture)&read); | |||||
| return r; | |||||
| } | } | ||||
| /* TODO(sergey): For some unspeakable reason both GCC-6 and Clang-3.9 are | /* Tricubic b-spline interpolation. | ||||
| * | |||||
| * 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 | ||||
| * enabled. | * enabled. | ||||
| */ | */ | ||||
| #if defined(__GNUC__) || defined(__clang__) | #if defined(__GNUC__) || defined(__clang__) | ||||
| static ccl_always_inline | static ccl_always_inline | ||||
| #else | #else | ||||
| static ccl_never_inline | static ccl_never_inline | ||||
| #endif | #endif | ||||
| float4 | float4 | ||||
| interp_3d_cubic(const TextureInfo &info, float x, float y, float z) | interp_3d_cubic(const TextureInfo &info, float x, float y, float z) | ||||
| { | { | ||||
| int width = info.width; | int pix, piy, piz; | ||||
| int height = info.height; | |||||
| int depth = info.depth; | |||||
| int ix, iy, iz; | int ix, iy, iz; | ||||
| int nix, niy, niz; | int nix, niy, niz; | ||||
| /* Tricubic b-spline interpolation. */ | int nnix, nniy, nniz; | ||||
| const float tx = frac(x * (float)width - 0.5f, &ix); | |||||
| const float ty = frac(y * (float)height - 0.5f, &iy); | /* A -0.5 offset is used to center the cubic samples around the sample point. */ | ||||
| const float tz = frac(z * (float)depth - 0.5f, &iz); | const float tx = frac(x * (float)info.width - 0.5f, &ix); | ||||
| int pix, piy, piz, nnix, nniy, nniz; | const float ty = frac(y * (float)info.height - 0.5f, &iy); | ||||
| const float tz = frac(z * (float)info.depth - 0.5f, &iz); | |||||
| switch (info.extension) { | switch (info.extension) { | ||||
| case EXTENSION_REPEAT: | case EXTENSION_REPEAT: | ||||
| ix = wrap_periodic(ix, width); | ix = wrap_periodic(ix, info.width); | ||||
| iy = wrap_periodic(iy, height); | pix = wrap_periodic(ix - 1, info.width); | ||||
| iz = wrap_periodic(iz, depth); | nix = wrap_periodic(ix + 1, info.width); | ||||
| nnix = wrap_periodic(ix + 2, info.width); | |||||
| pix = wrap_periodic(ix - 1, width); | |||||
| piy = wrap_periodic(iy - 1, height); | iy = wrap_periodic(iy, info.height); | ||||
| piz = wrap_periodic(iz - 1, depth); | niy = wrap_periodic(iy + 1, info.height); | ||||
| piy = wrap_periodic(iy - 1, info.height); | |||||
| nix = wrap_periodic(ix + 1, width); | nniz = wrap_periodic(iz + 2, info.depth); | ||||
| niy = wrap_periodic(iy + 1, height); | |||||
| niz = wrap_periodic(iz + 1, depth); | iz = wrap_periodic(iz, info.depth); | ||||
| piz = wrap_periodic(iz - 1, info.depth); | |||||
| nnix = wrap_periodic(ix + 2, width); | niz = wrap_periodic(iz + 1, info.depth); | ||||
| nniy = wrap_periodic(iy + 2, height); | nniy = wrap_periodic(iy + 2, info.height); | ||||
| nniz = wrap_periodic(iz + 2, depth); | break; | ||||
| break; | case EXTENSION_CLIP: { | ||||
| case EXTENSION_CLIP: | /* Case - No cubic samples are inside the clip region. */ | ||||
| if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { | if (ix < -2 || ix > info.width || iy < -2 || iy > info.height || iz < -2 || | ||||
| iz > info.depth) { | |||||
| return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | return make_float4(0.0f, 0.0f, 0.0f, 0.0f); | ||||
| } | } | ||||
| ATTR_FALLTHROUGH; | |||||
| pix = ix - 1; | |||||
| nnix = ix + 2; | |||||
| nix = ix + 1; | |||||
| piy = iy - 1; | |||||
| niy = iy + 1; | |||||
| nniy = iy + 2; | |||||
| piz = iz - 1; | |||||
| niz = iz + 1; | |||||
| nniz = iz + 2; | |||||
| /* Case - All linear samples are inside the clip region. */ | |||||
| if (pix >= 0 && nnix < info.width && piy >= 0 && nniy < info.height && piz >= 0 && | |||||
| nniz < info.depth) { | |||||
| break; | |||||
| } | |||||
| /* Case - The Cubic samples span the clip border. | |||||
| * #read_clip is used to ensure proper interpolation across the clip border. */ | |||||
| const int xc[4] = {pix, ix, nix, nnix}; | |||||
| const int yc[4] = {piy, iy, niy, nniy}; | |||||
| const int zc[4] = {piz, iz, niz, nniz}; | |||||
| return tricubic_lookup((const T *)info.data, | |||||
| tx, | |||||
| ty, | |||||
| tz, | |||||
| xc, | |||||
| yc, | |||||
| zc, | |||||
| info.width, | |||||
| info.height, | |||||
| info.depth, | |||||
| (ReadType3DTexture)&read_clip); | |||||
| } | |||||
| case EXTENSION_EXTEND: | case EXTENSION_EXTEND: | ||||
| pix = wrap_clamp(ix - 1, width); | pix = wrap_clamp(ix - 1, info.width); | ||||
| piy = wrap_clamp(iy - 1, height); | nix = wrap_clamp(ix + 1, info.width); | ||||
| piz = wrap_clamp(iz - 1, depth); | nnix = wrap_clamp(ix + 2, info.width); | ||||
| ix = wrap_clamp(ix, info.width); | |||||
| nix = wrap_clamp(ix + 1, width); | |||||
| niy = wrap_clamp(iy + 1, height); | piy = wrap_clamp(iy - 1, info.height); | ||||
| niz = wrap_clamp(iz + 1, depth); | niy = wrap_clamp(iy + 1, info.height); | ||||
| nniy = wrap_clamp(iy + 2, info.height); | |||||
| nnix = wrap_clamp(ix + 2, width); | iy = wrap_clamp(iy, info.height); | ||||
| nniy = wrap_clamp(iy + 2, height); | |||||
| nniz = wrap_clamp(iz + 2, depth); | piz = wrap_clamp(iz - 1, info.depth); | ||||
| niz = wrap_clamp(iz + 1, info.depth); | |||||
| ix = wrap_clamp(ix, width); | nniz = wrap_clamp(iz + 2, info.depth); | ||||
| iy = wrap_clamp(iy, height); | iz = wrap_clamp(iz, info.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}; | return tricubic_lookup((const T *)info.data, | ||||
| float u[4], v[4], w[4]; | tx, | ||||
| ty, | |||||
| /* Some helper macro to keep code reasonable size, | tz, | ||||
| * let compiler to inline all the matrix multiplications. | xc, | ||||
| */ | yc, | ||||
| #define DATA(x, y, z) (read(data[xc[x] + yc[y] + zc[z]])) | zc, | ||||
| #define COL_TERM(col, row) \ | info.width, | ||||
| (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \ | info.height, | ||||
| u[3] * DATA(3, col, row))) | info.depth, | ||||
| #define ROW_TERM(row) \ | (ReadType3DTexture)&read); | ||||
| (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(v, ty); | |||||
| SET_CUBIC_SPLINE_WEIGHTS(w, tz); | |||||
| /* Actual interpolation. */ | |||||
| const T *data = (const T *)info.data; | |||||
| return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3); | |||||
| #undef COL_TERM | |||||
| #undef ROW_TERM | |||||
| #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 All 29 Lines | static ccl_always_inline float4 interp_3d_linear(const AccessorType &acc, | ||||
| float x, | float x, | ||||
| float y, | float y, | ||||
| float z) | float z) | ||||
| { | { | ||||
| const nanovdb::Vec3f xyz(x - 0.5f, y - 0.5f, z - 0.5f); | const nanovdb::Vec3f xyz(x - 0.5f, y - 0.5f, z - 0.5f); | ||||
| return read(nanovdb::SampleFromVoxels<AccessorType, 1, false>(acc)(xyz)); | return read(nanovdb::SampleFromVoxels<AccessorType, 1, false>(acc)(xyz)); | ||||
| } | } | ||||
| /* Tricubic b-spline interpolation. */ | |||||
| # if defined(__GNUC__) || defined(__clang__) | # if defined(__GNUC__) || defined(__clang__) | ||||
| static ccl_always_inline | static ccl_always_inline | ||||
| # else | # else | ||||
| static ccl_never_inline | static ccl_never_inline | ||||
| # endif | # endif | ||||
| float4 | float4 | ||||
| interp_3d_cubic(const AccessorType &acc, float x, float y, float z) | interp_3d_cubic(const AccessorType &acc, float x, float y, float z) | ||||
| { | { | ||||
| int ix, iy, iz; | int ix, iy, iz; | ||||
| int nix, niy, niz; | int nix, niy, niz; | ||||
| int pix, piy, piz; | int pix, piy, piz; | ||||
| int nnix, nniy, nniz; | int nnix, nniy, nniz; | ||||
| /* Tricubic b-spline interpolation. */ | |||||
| /* A -0.5 offset is used to center the cubic samples around the sample point. */ | |||||
| const float tx = frac(x - 0.5f, &ix); | const float tx = frac(x - 0.5f, &ix); | ||||
| const float ty = frac(y - 0.5f, &iy); | const float ty = frac(y - 0.5f, &iy); | ||||
| const float tz = frac(z - 0.5f, &iz); | const float tz = frac(z - 0.5f, &iz); | ||||
| pix = ix - 1; | pix = ix - 1; | ||||
| piy = iy - 1; | piy = iy - 1; | ||||
| piz = iz - 1; | piz = iz - 1; | ||||
| nix = ix + 1; | nix = ix + 1; | ||||
| niy = iy + 1; | niy = iy + 1; | ||||
| niz = iz + 1; | niz = iz + 1; | ||||
| nnix = ix + 2; | nnix = ix + 2; | ||||
| nniy = iy + 2; | nniy = iy + 2; | ||||
| nniz = iz + 2; | nniz = iz + 2; | ||||
| 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}; | ||||
| const int zc[4] = {piz, iz, niz, nniz}; | const int zc[4] = {piz, iz, niz, 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 macros to keep code size reasonable. | ||||
| * let compiler to inline all the matrix multiplications. | * Lets the compiler inline all the matrix multiplications. | ||||
| */ | */ | ||||
| # define DATA(x, y, z) (read(acc.getValue(nanovdb::Coord(xc[x], yc[y], zc[z])))) | # define DATA(x, y, z) (read(acc.getValue(nanovdb::Coord(xc[x], yc[y], zc[z])))) | ||||
| # 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))) | ||||
| ▲ Show 20 Lines • Show All 106 Lines • Show Last 20 Lines | |||||