[Bf-blender-cvs] [3a65d2f5911] blender-v3.4-release: Fix T101211: Image jitters when scaling by large values

Richard Antalik noreply at git.blender.org
Sun Nov 27 21:42:00 CET 2022


Commit: 3a65d2f5911cef65590c208fb8bccd5e10a4b29a
Author: Richard Antalik
Date:   Sun Nov 27 21:33:05 2022 +0100
Branches: blender-v3.4-release
https://developer.blender.org/rB3a65d2f5911cef65590c208fb8bccd5e10a4b29a

Fix T101211: Image jitters when scaling by large values

Issue was caused by imprecise math due to using float numbers.
Use double instead.

No negative performance impact was observed.

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D16517

===================================================================

M	source/blender/blenlib/BLI_math_vector.h
M	source/blender/blenlib/intern/math_vector_inline.c
M	source/blender/imbuf/intern/transform.cc

===================================================================

diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 17fe25ec67b..a796888902e 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -133,6 +133,7 @@ MINLINE void add_v4_v4v4(float r[4], const float a[4], const float b[4]);
 MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3]);
 
 MINLINE void sub_v2_v2(float r[2], const float a[2]);
+MINLINE void sub_v2_v2_db(double r[2], const double a[2]);
 MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2]);
 MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2]);
 MINLINE void sub_v2_v2v2_int(int r[2], const int a[2], const int b[2]);
@@ -193,6 +194,7 @@ MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f);
 MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f);
 MINLINE void madd_v3_v3v3(float r[3], const float a[3], const float b[3]);
 MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f);
+MINLINE void madd_v2_v2db_db(double r[2], const double a[2], const double b[2], double f);
 MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f);
 MINLINE void madd_v3_v3v3db_db(double r[3], const double a[3], const double b[3], double f);
 MINLINE void madd_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 27c17a90f5f..822a9157316 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -463,6 +463,12 @@ MINLINE void sub_v2_v2(float r[2], const float a[2])
   r[1] -= a[1];
 }
 
+MINLINE void sub_v2_v2_db(double r[2], const double a[2])
+{
+  r[0] -= a[0];
+  r[1] -= a[1];
+}
+
 MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
 {
   r[0] = a[0] - b[0];
@@ -697,6 +703,12 @@ MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], floa
   r[1] = a[1] + b[1] * f;
 }
 
+MINLINE void madd_v2_v2db_db(double r[2], const double a[2], const double b[2], double f)
+{
+  r[0] = a[0] + b[0] * f;
+  r[1] = a[1] + b[1] * f;
+}
+
 MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
 {
   r[0] = a[0] + b[0] * f;
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index 6d3452c64db..420cad06959 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -22,19 +22,19 @@ struct TransformUserData {
   /** \brief Destination image buffer to write to. */
   ImBuf *dst;
   /** \brief UV coordinates at the origin (0,0) in source image space. */
-  float start_uv[2];
+  double start_uv[2];
 
   /**
    * \brief delta UV coordinates along the source image buffer, when moving a single pixel in the X
    * axis of the dst image buffer.
    */
-  float add_x[2];
+  double add_x[2];
 
   /**
    * \brief delta UV coordinate along the source image buffer, when moving a single pixel in the Y
    * axes of the dst image buffer.
    */
-  float add_y[2];
+  double add_y[2];
 
   /**
    * \brief Cropping region in source image pixel space.
@@ -54,39 +54,45 @@ struct TransformUserData {
  private:
   void init_start_uv(const float transform_matrix[4][4])
   {
-    float start_uv_v3[3];
-    float orig[3];
-    zero_v3(orig);
-    mul_v3_m4v3(start_uv_v3, transform_matrix, orig);
-    copy_v2_v2(start_uv, start_uv_v3);
+    double start_uv_v3[3];
+    double orig[3];
+    double transform_matrix_double[4][4];
+    copy_m4d_m4(transform_matrix_double, transform_matrix);
+    zero_v3_db(orig);
+    mul_v3_m4v3_db(start_uv_v3, transform_matrix_double, orig);
+    copy_v2_v2_db(start_uv, start_uv_v3);
   }
 
   void init_add_x(const float transform_matrix[4][4])
   {
+    double transform_matrix_double[4][4];
+    copy_m4d_m4(transform_matrix_double, transform_matrix);
     const int width = src->x;
-    float add_x_v3[3];
-    float uv_max_x[3];
-    zero_v3(uv_max_x);
+    double add_x_v3[3];
+    double uv_max_x[3];
+    zero_v3_db(uv_max_x);
     uv_max_x[0] = width;
     uv_max_x[1] = 0.0f;
-    mul_v3_m4v3(add_x_v3, transform_matrix, uv_max_x);
-    sub_v2_v2(add_x_v3, start_uv);
-    mul_v2_fl(add_x_v3, 1.0f / width);
-    copy_v2_v2(add_x, add_x_v3);
+    mul_v3_m4v3_db(add_x_v3, transform_matrix_double, uv_max_x);
+    sub_v2_v2_db(add_x_v3, start_uv);
+    mul_v3db_db(add_x_v3, 1.0f / width);
+    copy_v2_v2_db(add_x, add_x_v3);
   }
 
   void init_add_y(const float transform_matrix[4][4])
   {
+    double transform_matrix_double[4][4];
+    copy_m4d_m4(transform_matrix_double, transform_matrix);
     const int height = src->y;
-    float add_y_v3[3];
-    float uv_max_y[3];
-    zero_v3(uv_max_y);
+    double add_y_v3[3];
+    double uv_max_y[3];
+    zero_v3_db(uv_max_y);
     uv_max_y[0] = 0.0f;
     uv_max_y[1] = height;
-    mul_v3_m4v3(add_y_v3, transform_matrix, uv_max_y);
-    sub_v2_v2(add_y_v3, start_uv);
-    mul_v2_fl(add_y_v3, 1.0f / height);
-    copy_v2_v2(add_y, add_y_v3);
+    mul_v3_m4v3_db(add_y_v3, transform_matrix_double, uv_max_y);
+    sub_v2_v2_db(add_y_v3, start_uv);
+    mul_v3db_db(add_y_v3, 1.0f / height);
+    copy_v2_v2_db(add_y, add_y_v3);
   }
 };
 
@@ -104,7 +110,7 @@ class BaseDiscard {
   /**
    * \brief Should the source pixel at the given uv coordinate be discarded.
    */
-  virtual bool should_discard(const TransformUserData &user_data, const float uv[2]) = 0;
+  virtual bool should_discard(const TransformUserData &user_data, const double uv[2]) = 0;
 };
 
 /**
@@ -117,7 +123,7 @@ class CropSource : public BaseDiscard {
    *
    * Uses user_data.src_crop to determine if the uv coordinate should be skipped.
    */
-  bool should_discard(const TransformUserData &user_data, const float uv[2]) override
+  bool should_discard(const TransformUserData &user_data, const double uv[2]) override
   {
     return uv[0] < user_data.src_crop.xmin || uv[0] >= user_data.src_crop.xmax ||
            uv[1] < user_data.src_crop.ymin || uv[1] >= user_data.src_crop.ymax;
@@ -134,7 +140,7 @@ class NoDiscard : public BaseDiscard {
    *
    * Will never discard any pixels.
    */
-  bool should_discard(const TransformUserData & /*user_data*/, const float /*uv*/[2]) override
+  bool should_discard(const TransformUserData & /*user_data*/, const double /*uv*/[2]) override
   {
     return false;
   }
@@ -202,12 +208,12 @@ class BaseUVWrapping {
   /**
    * \brief modify the given u coordinate.
    */
-  virtual float modify_u(const ImBuf *source_buffer, float u) = 0;
+  virtual double modify_u(const ImBuf *source_buffer, double u) = 0;
 
   /**
    * \brief modify the given v coordinate.
    */
-  virtual float modify_v(const ImBuf *source_buffer, float v) = 0;
+  virtual double modify_v(const ImBuf *source_buffer, double v) = 0;
 };
 
 /**
@@ -215,12 +221,12 @@ class BaseUVWrapping {
  */
 class PassThroughUV : public BaseUVWrapping {
  public:
-  float modify_u(const ImBuf * /*source_buffer*/, float u) override
+  double modify_u(const ImBuf * /*source_buffer*/, double u) override
   {
     return u;
   }
 
-  float modify_v(const ImBuf * /*source_buffer*/, float v) override
+  double modify_v(const ImBuf * /*source_buffer*/, double v) override
   {
     return v;
   }
@@ -231,7 +237,7 @@ class PassThroughUV : public BaseUVWrapping {
  */
 class WrapRepeatUV : public BaseUVWrapping {
  public:
-  float modify_u(const ImBuf *source_buffer, float u) override
+  double modify_u(const ImBuf *source_buffer, double u) override
 
   {
     int x = int(floor(u));
@@ -242,7 +248,7 @@ class WrapRepeatUV : public BaseUVWrapping {
     return x;
   }
 
-  float modify_v(const ImBuf *source_buffer, float v) override
+  double modify_v(const ImBuf *source_buffer, double v) override
   {
     int y = int(floor(v));
     y = y % source_buffer->y;
@@ -284,24 +290,24 @@ class Sampler {
   static const int ChannelLen = NumChannels;
   using SampleType = std::array<StorageType, NumChannels>;
 
-  void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample)
+  void sample(const ImBuf *source, const double u, const double v, SampleType &r_sample)
   {
     if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
                   NumChannels == 4) {
-      const float wrapped_u = uv_wrapper.modify_u(source, u);
-      const float wrapped_v = uv_wrapper.modify_v(source, v);
+      const double wrapped_u = uv_wrapper.modify_u(source, u);
+      const double wrapped_v = uv_wrapper.modify_v(source, v);
       bilinear_interpolation_color_fl(source, nullptr, r_sample.data(), wrapped_u, wrapped_v);
     }
     else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, uchar> &&
                        NumChannels == 4) {
-      const float wrapped_u = uv_wrapper.modify_u(source, u);
-      const float wrapped_v = uv_wrapper.modify_v(source, v);
+      const double wrapped_u = uv_wrapper.modify_u(source, u);
+      const double wrapped_v = uv_wrapper.modify_v(source, v);
       nearest_interpolation_color_char(source, r_sample.data(), nullptr, wrapped_u, wrapped_v);
     }
     else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, uchar> &&
                        NumChannels == 4) {
-      const float wrapped_u = uv_wrapper.modify_u(source, u);
-      const float wrapped_v = uv_wrapper.modify_v(source, v);
+      const double wrapped_u = uv_wrapper.modify_u(source, u);
+      const double wrapped_v = uv_wrapper.modify_v(source, v);
       bilinear_interpolation_color_char(source, r_sample.data(), nullptr, wrapped_u, wrapped_v);
     }
     else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
@@ -317,8 +323,8 @@ class Sampler {
                                            true);
       }
       else {
-        const float wrapped_u = uv_wrapper.modify_u(source, u);
-        const float wrapped_v = uv_wrapper.modify_v(source, v);
+        const double wrapped_u = uv_wrapper.modify_u(source, u);
+      

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list