Cycles: Cleanup, split 2D interpolation function

This commit is contained in:
Sergey Sharybin
2017-12-07 17:45:37 +01:00
parent 4a734325f7
commit f31fb4a014

View File

@@ -83,145 +83,160 @@ template<typename T> struct TextureInterpolator {
return x - (float)i; return x - (float)i;
} }
static ccl_always_inline float4 interp(const TextureInfo& info, float x, float y) /* ******** 2D interpolation ******** */
static ccl_always_inline float4 interp_closest(const TextureInfo& info,
float x, float y)
{ {
if(UNLIKELY(!info.data))
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
const T *data = (const T*)info.data; const T *data = (const T*)info.data;
int width = info.width; const int width = info.width;
int height = info.height; const int height = info.height;
int ix, iy;
frac(x*(float)width, &ix);
frac(y*(float)height, &iy);
switch(info.extension) {
case EXTENSION_REPEAT:
ix = wrap_periodic(ix, width);
iy = wrap_periodic(iy, 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;
case EXTENSION_EXTEND:
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
default:
kernel_assert(0);
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
return read(data[ix + iy*width]);
}
static ccl_always_inline float4 interp_linear(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, nix, niy; int ix, iy, nix, niy;
const float tx = frac(x*(float)width - 0.5f, &ix);
if(info.interpolation == INTERPOLATION_CLOSEST) { const float ty = frac(y*(float)height - 0.5f, &iy);
frac(x*(float)width, &ix); switch(info.extension) {
frac(y*(float)height, &iy); case EXTENSION_REPEAT:
switch(info.extension) { ix = wrap_periodic(ix, width);
case EXTENSION_REPEAT: iy = wrap_periodic(iy, height);
ix = wrap_periodic(ix, width); nix = wrap_periodic(ix+1, width);
iy = wrap_periodic(iy, height); niy = wrap_periodic(iy+1, 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 || y < 0.0f || x > 1.0f || y > 1.0f) {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
ATTR_FALLTHROUGH;
case EXTENSION_EXTEND:
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
default:
kernel_assert(0);
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[ix + iy*width]); ATTR_FALLTHROUGH;
case EXTENSION_EXTEND:
nix = wrap_clamp(ix+1, width);
niy = wrap_clamp(iy+1, height);
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
default:
kernel_assert(0);
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
} }
else if(info.interpolation == INTERPOLATION_LINEAR) { float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]);
float tx = frac(x*(float)width - 0.5f, &ix); r += (1.0f - ty)*tx*read(data[nix + iy*width]);
float ty = frac(y*(float)height - 0.5f, &iy); r += ty*(1.0f - tx)*read(data[ix + niy*width]);
r += ty*tx*read(data[nix + niy*width]);
return r;
}
switch(info.extension) { static ccl_always_inline float4 interp_cubic(const TextureInfo& info,
case EXTENSION_REPEAT: float x, float y)
ix = wrap_periodic(ix, width); {
iy = wrap_periodic(iy, height); const T *data = (const T*)info.data;
const int width = info.width;
nix = wrap_periodic(ix+1, width); const int height = info.height;
niy = wrap_periodic(iy+1, height); int ix, iy, nix, niy;
break; const float tx = frac(x*(float)width - 0.5f, &ix);
case EXTENSION_CLIP: const float ty = frac(y*(float)height - 0.5f, &iy);
if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { int pix, piy, nnix, nniy;
return make_float4(0.0f, 0.0f, 0.0f, 0.0f); switch(info.extension) {
} case EXTENSION_REPEAT:
ATTR_FALLTHROUGH; ix = wrap_periodic(ix, width);
case EXTENSION_EXTEND: iy = wrap_periodic(iy, height);
nix = wrap_clamp(ix+1, width); pix = wrap_periodic(ix-1, width);
niy = wrap_clamp(iy+1, height); piy = wrap_periodic(iy-1, height);
nix = wrap_periodic(ix+1, width);
ix = wrap_clamp(ix, width); niy = wrap_periodic(iy+1, height);
iy = wrap_clamp(iy, height); nnix = wrap_periodic(ix+2, width);
break; nniy = wrap_periodic(iy+2, height);
default: break;
kernel_assert(0); 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); return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
} }
ATTR_FALLTHROUGH;
float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]); case EXTENSION_EXTEND:
r += (1.0f - ty)*tx*read(data[nix + iy*width]); pix = wrap_clamp(ix-1, width);
r += ty*(1.0f - tx)*read(data[ix + niy*width]); piy = wrap_clamp(iy-1, height);
r += ty*tx*read(data[nix + niy*width]); nix = wrap_clamp(ix+1, width);
niy = wrap_clamp(iy+1, height);
return r; nnix = wrap_clamp(ix+2, width);
nniy = wrap_clamp(iy+2, height);
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
default:
kernel_assert(0);
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
} }
else { const int xc[4] = {pix, ix, nix, nnix};
/* Bicubic b-spline interpolation. */ const int yc[4] = {width * piy,
float tx = frac(x*(float)width - 0.5f, &ix); width * iy,
float ty = frac(y*(float)height - 0.5f, &iy); width * niy,
int pix, piy, nnix, nniy; width * nniy};
switch(info.extension) { float u[4], v[4];
case EXTENSION_REPEAT: /* Some helper macro to keep code reasonable size,
ix = wrap_periodic(ix, width); * let compiler to inline all the matrix multiplications.
iy = wrap_periodic(iy, height); */
pix = wrap_periodic(ix-1, width);
piy = wrap_periodic(iy-1, height);
nix = wrap_periodic(ix+1, width);
niy = wrap_periodic(iy+1, height);
nnix = wrap_periodic(ix+2, width);
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;
case EXTENSION_EXTEND:
pix = wrap_clamp(ix-1, width);
piy = wrap_clamp(iy-1, height);
nix = wrap_clamp(ix+1, width);
niy = wrap_clamp(iy+1, height);
nnix = wrap_clamp(ix+2, width);
nniy = wrap_clamp(iy+2, height);
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
default:
kernel_assert(0);
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};
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]]))
#define TERM(col) \ #define TERM(col) \
(v[col] * (u[0] * DATA(0, col) + \ (v[col] * (u[0] * DATA(0, col) + \
u[1] * DATA(1, col) + \ u[1] * DATA(1, col) + \
u[2] * DATA(2, col) + \ u[2] * DATA(2, col) + \
u[3] * DATA(3, 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. */
return TERM(0) + TERM(1) + TERM(2) + TERM(3);
/* Actual interpolation. */
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)
{
if(UNLIKELY(!info.data)) {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
switch(info.interpolation) {
case INTERPOLATION_CLOSEST:
return interp_closest(info, x, y);
case INTERPOLATION_LINEAR:
return interp_linear(info, x, y);
default:
return interp_cubic(info, x, y);
} }
} }
static ccl_always_inline float4 interp_3d_closest(const TextureInfo& info, float x, float y, float z) /* ******** 3D interpolation ******** */
static ccl_always_inline float4 interp_3d_closest(const TextureInfo& info,
float x, float y, float z)
{ {
int width = info.width; int width = info.width;
int height = info.height; int height = info.height;
@@ -259,7 +274,8 @@ template<typename T> struct TextureInterpolator {
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, float x, float y, float z) static ccl_always_inline float4 interp_3d_linear(const TextureInfo& info,
float x, float y, float z)
{ {
int width = info.width; int width = info.width;
int height = info.height; int height = info.height;