[Bf-blender-cvs] [cb54fae36cf] temp-gpu-image-engine: Added support for 3 channel source buffers.

Jeroen Bakker noreply at git.blender.org
Mon Dec 13 12:47:44 CET 2021


Commit: cb54fae36cf0d7ac9cb66508074f89a96449404e
Author: Jeroen Bakker
Date:   Mon Dec 13 11:05:31 2021 +0100
Branches: temp-gpu-image-engine
https://developer.blender.org/rBcb54fae36cf0d7ac9cb66508074f89a96449404e

Added support for 3 channel source buffers.

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

M	source/blender/imbuf/intern/transform.cc

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

diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index 8bfca373aee..a62e65b7a7d 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -21,6 +21,7 @@
  * \ingroup imbuf
  */
 
+#include <array>
 #include <type_traits>
 
 #include "BLI_math.h"
@@ -151,6 +152,10 @@ template<
      */
     int NumChannels = 4>
 class TexelPointer {
+ public:
+  static const int ChannelLen = NumChannels;
+
+ private:
   StorageType *pointer;
 
  public:
@@ -170,26 +175,6 @@ class TexelPointer {
       pointer = nullptr;
     }
   }
-  /*
-    float *get_float_pointer()
-    {
-      if constexpr (std::is_same_v<StorageType, float>) {
-        return pointer;
-      }
-      else {
-        return nullptr;
-      }
-    }
-    unsigned char *get_uchar_pointer()
-    {
-      if constexpr (std::is_same_v<StorageType, unsigned char>) {
-        return pointer;
-      }
-      else {
-        return nullptr;
-      }
-    }
-    */
 
   /**
    * \brief Get pointer to the current texel to write to.
@@ -207,6 +192,10 @@ class TexelPointer {
 
 template<eIMBInterpolationFilterMode Filter, typename StorageType, int NumChannels> class Sampler {
  public:
+  using ChannelType = StorageType;
+  static const int ChannelLen = NumChannels;
+  using SampleType = std::array<StorageType, NumChannels>;
+
   virtual void sample(const ImBuf *source,
                       const float u,
                       const float v,
@@ -235,6 +224,44 @@ template<eIMBInterpolationFilterMode Filter, typename StorageType, int NumChanne
   }
 };
 
+/**
+ * \brief Change the number of channels and store it.
+ *
+ * Template class to convert and store a sample in a TexelPointer.
+ * It supports:
+ * - 4 channel unsigned char -> 4 channel unsigned char.
+ * - 4 channel float -> 4 channel float.
+ * - 3 channel float -> 4 channel float.
+ */
+template<typename StorageType, int SourceNumChannels, int DestinationNumChannels>
+class ChannelConverter {
+ public:
+  using SampleType = std::array<StorageType, SourceNumChannels>;
+  using TexelType = TexelPointer<StorageType, DestinationNumChannels>;
+
+  /**
+   * \brief Convert the number of channels of the given sample to match the texel pointer and store
+   * it at the location the texel_pointer points at.
+   */
+  void convert_and_store(const SampleType &sample, TexelType &texel_pointer)
+  {
+    if constexpr (std::is_same_v<StorageType, unsigned char>) {
+      BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels.");
+      BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels.");
+
+      copy_v4_v4_uchar(texel_pointer.get_pointer(), sample.begin());
+    }
+    else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
+                       DestinationNumChannels == 4) {
+      copy_v4_v4(texel_pointer.get_pointer(), sample.begin());
+    }
+    else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
+                       DestinationNumChannels == 4) {
+      copy_v4_fl4(texel_pointer.get_pointer(), sample[0], sample[1], sample[2], 1.0f);
+    }
+  }
+};
+
 /**
  * \brief Wrapping mode for the uv coordinates.
  *
@@ -326,6 +353,10 @@ class ScanlineProcessor {
   UVWrapping uv_wrapping;
   OutputTexelPointer output;
   Sampler sampler;
+  ChannelConverter<typename Sampler::ChannelType,
+                   Sampler::ChannelLen,
+                   OutputTexelPointer::ChannelLen>
+      channel_converter;
 
  public:
   void process(const TransformUserData *user_data, int scanline)
@@ -338,11 +369,12 @@ class ScanlineProcessor {
     output.init_pixel_pointer(user_data->dst, 0, scanline);
     for (int xi = 0; xi < width; xi++) {
       if (!discarder.should_discard(*user_data, uv)) {
-
+        typename Sampler::SampleType sample;
         sampler.sample(user_data->src,
                        uv_wrapping.modify_u(*user_data, uv[0]),
                        uv_wrapping.modify_v(*user_data, uv[1]),
-                       output.get_pointer());
+                       &sample[0]);
+        channel_converter.convert_and_store(sample, output);
       }
 
       add_v2_v2(uv, user_data->add_x);
@@ -358,7 +390,10 @@ template<typename Processor> void transform_scanline_function(void *custom_data,
   processor.process(user_data, scanline);
 }
 
-template<eIMBInterpolationFilterMode Filter, typename StorageType, int NumChannels>
+template<eIMBInterpolationFilterMode Filter,
+         typename StorageType,
+         int SourceNumChannels,
+         int DestinationNumChannels>
 ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
 
 {
@@ -366,20 +401,20 @@ ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
     case IMB_TRANSFORM_MODE_REGULAR:
       return transform_scanline_function<
           ScanlineProcessor<NoDiscard,
-                            Sampler<Filter, StorageType, NumChannels>,
-                            TexelPointer<StorageType, NumChannels>,
+                            Sampler<Filter, StorageType, SourceNumChannels>,
+                            TexelPointer<StorageType, DestinationNumChannels>,
                             PassThroughUV>>;
     case IMB_TRANSFORM_MODE_CROP_SRC:
       return transform_scanline_function<
           ScanlineProcessor<CropSource,
-                            Sampler<Filter, StorageType, NumChannels>,
-                            TexelPointer<StorageType, NumChannels>,
+                            Sampler<Filter, StorageType, SourceNumChannels>,
+                            TexelPointer<StorageType, DestinationNumChannels>,
                             PassThroughUV>>;
     case IMB_TRANSFORM_MODE_WRAP_REPEAT:
       return transform_scanline_function<
           ScanlineProcessor<NoDiscard,
-                            Sampler<Filter, StorageType, NumChannels>,
-                            TexelPointer<StorageType, NumChannels>,
+                            Sampler<Filter, StorageType, SourceNumChannels>,
+                            TexelPointer<StorageType, DestinationNumChannels>,
                             WrapRepeatUV>>;
   }
 
@@ -387,16 +422,36 @@ ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
   return nullptr;
 }
 
+template<eIMBInterpolationFilterMode Filter>
+ScanlineThreadFunc get_scanline_function(const TransformUserData *user_data,
+                                         const eIMBTransformMode mode)
+{
+  const ImBuf *src = user_data->src;
+  const ImBuf *dst = user_data->dst;
+
+  if (src->channels == 4 && dst->channels == 4) {
+    return get_scanline_function<Filter, float, 4, 4>(mode);
+  }
+  if (src->channels == 3 && dst->channels == 4) {
+    return get_scanline_function<Filter, float, 3, 4>(mode);
+  }
+  if (src->channels == 3 && dst->channels == 4) {
+    return get_scanline_function<Filter, float, 3, 4>(mode);
+  }
+  return nullptr;
+}
+
 template<eIMBInterpolationFilterMode Filter>
 static void transform(TransformUserData *user_data, const eIMBTransformMode mode)
 {
   ScanlineThreadFunc scanline_func = nullptr;
 
   if (user_data->dst->rect_float) {
-    scanline_func = get_scanline_function<Filter, float, 4>(mode);
+    scanline_func = get_scanline_function<Filter>(user_data, mode);
   }
   else if (user_data->dst->rect) {
-    scanline_func = get_scanline_function<Filter, unsigned char, 4>(mode);
+    /* Number of channels is always 4 when using unsigned char buffers (sRGB + straight alpha). */
+    scanline_func = get_scanline_function<Filter, unsigned char, 4, 4>(mode);
   }
 
   if (scanline_func != nullptr) {



More information about the Bf-blender-cvs mailing list