Cycles: OpenCL bicubic and tricubic texture interpolation support.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 8 Oct 2017 00:36:05 +0000 (02:36 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 8 Oct 2017 00:55:44 +0000 (02:55 +0200)
intern/cycles/blender/addon/ui.py
intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h
intern/cycles/util/util_texture.h
source/blender/makesrna/intern/rna_nodetree.c

index baf1b9c31eef2919a262596f15baa3edad867c2a..7d19bccae4ede3fe9cb5219d4c6e94bc580dc156 100644 (file)
@@ -1208,9 +1208,7 @@ class CYCLES_WORLD_PT_settings(CyclesButtonsPanel, Panel):
         sub = col.column()
         sub.active = use_cpu(context)
         sub.prop(cworld, "volume_sampling", text="")
-        sub = col.column()
-        sub.active = not use_opencl(context)
-        sub.prop(cworld, "volume_interpolation", text="")
+        col.prop(cworld, "volume_interpolation", text="")
         col.prop(cworld, "homogeneous_volume", text="Homogeneous")
 
 
@@ -1309,9 +1307,7 @@ class CYCLES_MATERIAL_PT_settings(CyclesButtonsPanel, Panel):
         sub = col.column()
         sub.active = use_cpu(context)
         sub.prop(cmat, "volume_sampling", text="")
-        sub = col.column()
-        sub.active = not use_opencl(context)
-        sub.prop(cmat, "volume_interpolation", text="")
+        col.prop(cmat, "volume_interpolation", text="")
         col.prop(cmat, "homogeneous_volume", text="Homogeneous")
 
         layout.separator()
index 20ec36aa9eb5f3806cc19c2d1e95d0301764e496..d908af78c7a3637936b382428c7311d030963036 100644 (file)
@@ -75,20 +75,26 @@ ccl_device_inline float svm_image_texture_frac(float x, int *ix)
        return x - (float)i;
 }
 
+#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[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[3] = (1.0f / 6.0f) * t * t * t; \
+       } (void)0
+
 ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y)
 {
        const ccl_global TextureInfo *info = kernel_tex_info(kg, id);
 
        uint width = info->width;
        uint height = info->height;
-       uint offset = 0;
        uint interpolation = info->interpolation;
        uint extension = info->extension;
 
        /* Actual sampling. */
-       float4 r;
-       int ix, iy, nix, niy;
        if(interpolation == INTERPOLATION_CLOSEST) {
+               int ix, iy;
                svm_image_texture_frac(x*width, &ix);
                svm_image_texture_frac(y*height, &iy);
 
@@ -108,16 +114,17 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
                        iy = svm_image_texture_wrap_clamp(iy, height);
                }
 
-               r = svm_image_texture_read(kg, id, offset + ix + iy*width);
+               return svm_image_texture_read(kg, id, ix + iy*width);
        }
-       else { /* INTERPOLATION_LINEAR */
+       else {
+               /* Bilinear or bicubic interpolation. */
+               int ix, iy, nix, niy;
                float tx = svm_image_texture_frac(x*width - 0.5f, &ix);
                float ty = svm_image_texture_frac(y*height - 0.5f, &iy);
 
                if(extension == EXTENSION_REPEAT) {
                        ix = svm_image_texture_wrap_periodic(ix, width);
                        iy = svm_image_texture_wrap_periodic(iy, height);
-
                        nix = svm_image_texture_wrap_periodic(ix+1, width);
                        niy = svm_image_texture_wrap_periodic(iy+1, height);
                }
@@ -127,18 +134,61 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl
                                        return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
                                }
                        }
-                       nix = svm_image_texture_wrap_clamp(ix+1, width);
-                       niy = svm_image_texture_wrap_clamp(iy+1, height);
                        ix = svm_image_texture_wrap_clamp(ix, width);
                        iy = svm_image_texture_wrap_clamp(iy, height);
+                       nix = svm_image_texture_wrap_clamp(ix+1, width);
+                       niy = svm_image_texture_wrap_clamp(iy+1, height);
                }
 
-               r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width);
-               r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width);
-               r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width);
-               r += ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width);
+               if(interpolation == INTERPOLATION_LINEAR) {
+                       /* Bilinear interpolation. */
+                       float4 r;
+                       r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, ix + iy*width);
+                       r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, nix + iy*width);
+                       r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, ix + niy*width);
+                       r += ty*tx*svm_image_texture_read(kg, id, nix + niy*width);
+                       return r;
+               }
+
+               /* Bicubic interpolation. */
+               int pix, piy, nnix, nniy;
+               if(extension == EXTENSION_REPEAT) {
+                       pix = svm_image_texture_wrap_periodic(ix-1, width);
+                       piy = svm_image_texture_wrap_periodic(iy-1, height);
+                       nnix = svm_image_texture_wrap_periodic(ix+2, width);
+                       nniy = svm_image_texture_wrap_periodic(iy+2, height);
+               }
+               else {
+                       pix = svm_image_texture_wrap_clamp(ix-1, width);
+                       piy = svm_image_texture_wrap_clamp(iy-1, height);
+                       nnix = svm_image_texture_wrap_clamp(ix+2, width);
+                       nniy = svm_image_texture_wrap_clamp(iy+2, height);
+               }
+
+               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) (svm_image_texture_read(kg, id, xc[x] + yc[y]))
+#define TERM(col) \
+               (v[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(v, ty);
+
+               /* Actual interpolation. */
+               return TERM(0) + TERM(1) + TERM(2) + TERM(3);
+#undef TERM
+#undef DATA
        }
-       return r;
 }
 
 
@@ -148,15 +198,13 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x,
 
        uint width = info->width;
        uint height = info->height;
-       uint offset = 0;
        uint depth = info->depth;
        uint interpolation = (interp == INTERPOLATION_NONE)? info->interpolation: interp;
        uint extension = info->extension;
 
        /* Actual sampling. */
-       float4 r;
-       int ix, iy, iz, nix, niy, niz;
        if(interpolation == INTERPOLATION_CLOSEST) {
+               int ix, iy, iz;
                svm_image_texture_frac(x*width, &ix);
                svm_image_texture_frac(y*height, &iy);
                svm_image_texture_frac(z*depth, &iz);
@@ -180,9 +228,11 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x,
                        iy = svm_image_texture_wrap_clamp(iy, height);
                        iz = svm_image_texture_wrap_clamp(iz, depth);
                }
-               r = svm_image_texture_read(kg, id, offset + ix + iy*width + iz*width*height);
+               return svm_image_texture_read(kg, id, ix + iy*width + iz*width*height);
        }
-       else { /* INTERPOLATION_LINEAR */
+       else {
+               /* Bilinear or bicubic interpolation. */
+               int ix, iy, iz, nix, niy, niz;
                float tx = svm_image_texture_frac(x*(float)width - 0.5f, &ix);
                float ty = svm_image_texture_frac(y*(float)height - 0.5f, &iy);
                float tz = svm_image_texture_frac(z*(float)depth - 0.5f, &iz);
@@ -215,15 +265,77 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x,
                        iz = svm_image_texture_wrap_clamp(iz, depth);
                }
 
-               r  = (1.0f - tz)*(1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width + iz*width*height);
-               r += (1.0f - tz)*(1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width + iz*width*height);
-               r += (1.0f - tz)*ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width + iz*width*height);
-               r += (1.0f - tz)*ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width + iz*width*height);
+               if(interpolation == INTERPOLATION_LINEAR) {
+                       /* Bilinear interpolation. */
+                       float4 r;
+                       r  = (1.0f - tz)*(1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, ix + iy*width + iz*width*height);
+                       r += (1.0f - tz)*(1.0f - ty)*tx*svm_image_texture_read(kg, id, nix + iy*width + iz*width*height);
+                       r += (1.0f - tz)*ty*(1.0f - tx)*svm_image_texture_read(kg, id, ix + niy*width + iz*width*height);
+                       r += (1.0f - tz)*ty*tx*svm_image_texture_read(kg, id, nix + niy*width + iz*width*height);
+
+                       r += tz*(1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, ix + iy*width + niz*width*height);
+                       r += tz*(1.0f - ty)*tx*svm_image_texture_read(kg, id, nix + iy*width + niz*width*height);
+                       r += tz*ty*(1.0f - tx)*svm_image_texture_read(kg, id, ix + niy*width + niz*width*height);
+                       r += tz*ty*tx*svm_image_texture_read(kg, id, nix + niy*width + niz*width*height);
+                       return r;
+               }
+
+               /* Bicubic interpolation. */
+               int pix, piy, piz, nnix, nniy, nniz;
+               if(extension == EXTENSION_REPEAT) {
+                       pix = svm_image_texture_wrap_periodic(ix-1, width);
+                       piy = svm_image_texture_wrap_periodic(iy-1, height);
+                       piz = svm_image_texture_wrap_periodic(iz-1, depth);
+                       nnix = svm_image_texture_wrap_periodic(ix+2, width);
+                       nniy = svm_image_texture_wrap_periodic(iy+2, height);
+                       nniz = svm_image_texture_wrap_periodic(iz+2, depth);
+               }
+               else {
+                       pix = svm_image_texture_wrap_clamp(ix-1, width);
+                       piy = svm_image_texture_wrap_clamp(iy-1, height);
+                       piz = svm_image_texture_wrap_clamp(iz-1, depth);
+                       nnix = svm_image_texture_wrap_clamp(ix+2, width);
+                       nniy = svm_image_texture_wrap_clamp(iy+2, height);
+                       nniz = svm_image_texture_wrap_clamp(iz+2, depth);
+               }
+
+               const int xc[4] = {pix, ix, nix, nnix};
+               const int yc[4] = {width * piy,
+                                  width * iy,
+                                  width * niy,
+                                  width * nniy};
+               const int zc[4] = {width * height * piz,
+                                  width * height * iz,
+                                  width * height * niz,
+                                  width * height * nniz};
+               float u[4], v[4], w[4];
+
+               /* Some helper macro to keep code reasonable size,
+                * let compiler to inline all the matrix multiplications.
+                */
+#define DATA(x, y, z) (svm_image_texture_read(kg, id, xc[x] + yc[y] + zc[z]))
+#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)))
 
-               r += tz*(1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width + niz*width*height);
-               r += tz*(1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width + niz*width*height);
-               r += tz*ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width + niz*width*height);
-               r += tz*ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width + niz*width*height);
+               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
        }
-       return r;
 }
+
+#undef SET_CUBIC_SPLINE_WEIGHTS
index f22948d9bcd4cafe2bd1b3e276854dce1844ab18..cec03dc5e6e8da94629de5141ee69ef5adbbe192 100644 (file)
@@ -52,7 +52,7 @@ CCL_NAMESPACE_BEGIN
 
 /* Interpolation types for textures
  * cuda also use texture space to store other objects */
-enum InterpolationType {
+typedef enum InterpolationType {
        INTERPOLATION_NONE = -1,
        INTERPOLATION_LINEAR = 0,
        INTERPOLATION_CLOSEST = 1,
@@ -60,12 +60,12 @@ enum InterpolationType {
        INTERPOLATION_SMART = 3,
 
        INTERPOLATION_NUM_TYPES,
-};
+} InterpolationType;
 
 /* Texture types
  * Since we store the type in the lower bits of a flat index,
  * the shift and bit mask constant below need to be kept in sync. */
-enum ImageDataType {
+typedef enum ImageDataType {
        IMAGE_DATA_TYPE_FLOAT4 = 0,
        IMAGE_DATA_TYPE_BYTE4 = 1,
        IMAGE_DATA_TYPE_HALF4 = 2,
@@ -74,7 +74,7 @@ enum ImageDataType {
        IMAGE_DATA_TYPE_HALF = 5,
 
        IMAGE_DATA_NUM_TYPES
-};
+} ImageDataType;
 
 #define IMAGE_DATA_TYPE_SHIFT 3
 #define IMAGE_DATA_TYPE_MASK 0x7
@@ -82,7 +82,7 @@ enum ImageDataType {
 /* Extension types for textures.
  *
  * Defines how the image is extrapolated past its original bounds. */
-enum ExtensionType {
+typedef enum ExtensionType {
        /* Cause the image to repeat horizontally and vertically. */
        EXTENSION_REPEAT = 0,
        /* Extend by repeating edge pixels of the image. */
@@ -91,7 +91,7 @@ enum ExtensionType {
        EXTENSION_CLIP = 2,
 
        EXTENSION_NUM_TYPES,
-};
+} ExtensionType;
 
 typedef struct TextureInfo {
        /* Pointer, offset or texture depending on device. */
index ee4608b550f0cf946ece2ecdf3d4569ead711557..523c5c219d8ee93f0877274d4480727877aa3e25 100644 (file)
@@ -3721,7 +3721,7 @@ static const EnumPropertyItem sh_tex_prop_interpolation_items[] = {
        {SHD_INTERP_CLOSEST, "Closest", 0, "Closest",
                             "No interpolation (sample closest texel)"},
        {SHD_INTERP_CUBIC,   "Cubic", 0, "Cubic",
-                            "Cubic interpolation (CPU only)"},
+                            "Cubic interpolation"},
        {SHD_INTERP_SMART,   "Smart", 0, "Smart",
                             "Bicubic when magnifying, else bilinear (OSL only)"},
        {0, NULL, 0, NULL, NULL}
@@ -4087,7 +4087,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
                {SHD_INTERP_LINEAR,  "Linear", 0, "Linear",
                                     "Linear interpolation"},
                {SHD_INTERP_CUBIC,   "Cubic", 0, "Cubic",
-                                    "Cubic interpolation (CPU only)"},
+                                    "Cubic interpolation"},
                {0, NULL, 0, NULL, NULL}
        };