From 2e8914549b677dd0101ea17f64183a98db281510 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 8 Dec 2017 11:20:12 +0100 Subject: [PATCH] Cycles: Fix difference in image Clip extension method between CPU and GPU Our own implementation was behaving different comparing to OSL and GPU, namely on the border pixels OSL and CUDA was doing interpolation with black, but we were clamping coordinate. This partially fixes issue reported in T53452. Similar change should also be done for 3D interpolation perhaps, but this is to be investigated separately. --- .../kernel/kernels/cpu/kernel_cpu_image.h | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h index 8e9bae1d7d8..56c38d8101c 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h @@ -63,6 +63,16 @@ template struct TextureInterpolator { return make_float4(f, f, f, 1.0f); } + 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 make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + return read(data[y * width + x]); + } + static ccl_always_inline int wrap_periodic(int x, int width) { x %= width; @@ -132,10 +142,9 @@ template struct TextureInterpolator { niy = wrap_periodic(iy+1, height); break; case EXTENSION_CLIP: - if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - ATTR_FALLTHROUGH; + nix = ix + 1; + niy = iy + 1; + break; case EXTENSION_EXTEND: nix = wrap_clamp(ix+1, width); niy = wrap_clamp(iy+1, height); @@ -146,11 +155,10 @@ template struct TextureInterpolator { kernel_assert(0); return make_float4(0.0f, 0.0f, 0.0f, 0.0f); } - float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]); - r += (1.0f - ty)*tx*read(data[nix + iy*width]); - r += ty*(1.0f - tx)*read(data[ix + niy*width]); - r += ty*tx*read(data[nix + niy*width]); - return r; + return (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, width, height) + + (1.0f - ty) * tx * read(data, nix, iy, width, height) + + ty * (1.0f - tx) * read(data, ix, niy, width, height) + + ty * tx * read(data, nix, niy, width, height); } static ccl_always_inline float4 interp_cubic(const TextureInfo& info, @@ -175,10 +183,13 @@ template struct TextureInterpolator { nniy = wrap_periodic(iy+2, height); break; case EXTENSION_CLIP: - if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - ATTR_FALLTHROUGH; + pix = ix - 1; + piy = iy - 1; + nix = ix + 1; + niy = iy + 1; + nnix = ix + 2; + nniy = iy + 2; + break; case EXTENSION_EXTEND: pix = wrap_clamp(ix-1, width); piy = wrap_clamp(iy-1, height); @@ -194,15 +205,12 @@ template struct TextureInterpolator { return make_float4(0.0f, 0.0f, 0.0f, 0.0f); } 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}; float u[4], v[4]; /* Some helper macro to keep code reasonable size, * let compiler to inline all the matrix multiplications. */ -#define DATA(x, y) (read(data[xc[x] + yc[y]])) +#define DATA(x, y) (read(data, xc[x], yc[y], width, height)) #define TERM(col) \ (v[col] * (u[0] * DATA(0, col) + \ u[1] * DATA(1, col) + \ @@ -218,7 +226,8 @@ template struct TextureInterpolator { #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)) { return make_float4(0.0f, 0.0f, 0.0f, 0.0f);