[Bf-blender-cvs] [24e00c115c5] master: Fix T94712: Cycles missing colorspace transform on grayscale images

Brecht Van Lommel noreply at git.blender.org
Thu Jan 20 20:41:14 CET 2022


Commit: 24e00c115c5191da273e3ecf63f366ae7963bc57
Author: Brecht Van Lommel
Date:   Thu Jan 20 19:09:41 2022 +0100
Branches: master
https://developer.blender.org/rB24e00c115c5191da273e3ecf63f366ae7963bc57

Fix T94712: Cycles missing colorspace transform on grayscale images

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

M	intern/cycles/scene/colorspace.cpp
M	intern/cycles/scene/colorspace.h
M	intern/cycles/scene/image.cpp

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

diff --git a/intern/cycles/scene/colorspace.cpp b/intern/cycles/scene/colorspace.cpp
index c1a308fcbaa..f0b7eb724de 100644
--- a/intern/cycles/scene/colorspace.cpp
+++ b/intern/cycles/scene/colorspace.cpp
@@ -263,7 +263,9 @@ template<typename T> inline void cast_from_float4(T *data, float4 value)
 
 /* Slower versions for other all data types, which needs to convert to float and back. */
 template<typename T, bool compress_as_srgb = false>
-inline void processor_apply_pixels(const OCIO::Processor *processor, T *pixels, size_t num_pixels)
+inline void processor_apply_pixels_rgba(const OCIO::Processor *processor,
+                                        T *pixels,
+                                        size_t num_pixels)
 {
   /* TODO: implement faster version for when we know the conversion
    * is a simple matrix transform between linear spaces. In that case
@@ -310,25 +312,79 @@ inline void processor_apply_pixels(const OCIO::Processor *processor, T *pixels,
     }
   }
 }
+
+template<typename T, bool compress_as_srgb = false>
+inline void processor_apply_pixels_grayscale(const OCIO::Processor *processor,
+                                             T *pixels,
+                                             size_t num_pixels)
+{
+  OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
+
+  /* Process large images in chunks to keep temporary memory requirement down. */
+  const size_t chunk_size = std::min((size_t)(16 * 1024 * 1024), num_pixels);
+  vector<float> float_pixels(chunk_size * 3);
+
+  for (size_t j = 0; j < num_pixels; j += chunk_size) {
+    size_t width = std::min(chunk_size, num_pixels - j);
+
+    /* Convert to 3 channels, since that's the minimum required by OpenColorIO. */
+    {
+      const T *pixel = pixels + j;
+      float *fpixel = float_pixels.data();
+      for (size_t i = 0; i < width; i++, pixel++, fpixel += 3) {
+        const float f = util_image_cast_to_float<T>(*pixel);
+        fpixel[0] = f;
+        fpixel[1] = f;
+        fpixel[2] = f;
+      }
+    }
+
+    OCIO::PackedImageDesc desc((float *)float_pixels.data(), width, 1, 3);
+    device_processor->apply(desc);
+
+    {
+      T *pixel = pixels + j;
+      const float *fpixel = float_pixels.data();
+      for (size_t i = 0; i < width; i++, pixel++, fpixel += 3) {
+        float f = average(make_float3(fpixel[0], fpixel[1], fpixel[2]));
+        if (compress_as_srgb) {
+          f = color_linear_to_srgb(f);
+        }
+        *pixel = util_image_cast_from_float<T>(f);
+      }
+    }
+  }
+}
+
 #endif
 
 template<typename T>
-void ColorSpaceManager::to_scene_linear(ustring colorspace,
-                                        T *pixels,
-                                        size_t num_pixels,
-                                        bool compress_as_srgb)
+void ColorSpaceManager::to_scene_linear(
+    ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb)
 {
 #ifdef WITH_OCIO
   const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace);
 
   if (processor) {
-    if (compress_as_srgb) {
-      /* Compress output as sRGB. */
-      processor_apply_pixels<T, true>(processor, pixels, num_pixels);
+    if (is_rgba) {
+      if (compress_as_srgb) {
+        /* Compress output as sRGB. */
+        processor_apply_pixels_rgba<T, true>(processor, pixels, num_pixels);
+      }
+      else {
+        /* Write output as scene linear directly. */
+        processor_apply_pixels_rgba<T>(processor, pixels, num_pixels);
+      }
     }
     else {
-      /* Write output as scene linear directly. */
-      processor_apply_pixels<T>(processor, pixels, num_pixels);
+      if (compress_as_srgb) {
+        /* Compress output as sRGB. */
+        processor_apply_pixels_grayscale<T, true>(processor, pixels, num_pixels);
+      }
+      else {
+        /* Write output as scene linear directly. */
+        processor_apply_pixels_grayscale<T>(processor, pixels, num_pixels);
+      }
     }
   }
 #else
@@ -348,6 +404,11 @@ void ColorSpaceManager::to_scene_linear(ColorSpaceProcessor *processor_,
 
   if (processor) {
     OCIO::ConstCPUProcessorRcPtr device_processor = processor->getDefaultCPUProcessor();
+    if (channels == 1) {
+      float3 rgb = make_float3(pixel[0], pixel[0], pixel[0]);
+      device_processor->applyRGB(&rgb.x);
+      pixel[0] = average(rgb);
+    }
     if (channels == 3) {
       device_processor->applyRGB(pixel);
     }
@@ -390,9 +451,9 @@ void ColorSpaceManager::free_memory()
 }
 
 /* Template instantiations so we don't have to inline functions. */
-template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, bool);
-template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool);
-template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool);
-template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, uchar *, size_t, bool, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, ushort *, size_t, bool, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, half *, size_t, bool, bool);
+template void ColorSpaceManager::to_scene_linear(ustring, float *, size_t, bool, bool);
 
 CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/colorspace.h b/intern/cycles/scene/colorspace.h
index 7f7bc604f07..f02c1231a44 100644
--- a/intern/cycles/scene/colorspace.h
+++ b/intern/cycles/scene/colorspace.h
@@ -43,10 +43,8 @@ class ColorSpaceManager {
   /* Convert pixels in the specified colorspace to scene linear color for
    * rendering. Must be a colorspace returned from detect_known_colorspace. */
   template<typename T>
-  static void to_scene_linear(ustring colorspace,
-                              T *pixels,
-                              size_t num_pixels,
-                              bool compress_as_srgb);
+  static void to_scene_linear(
+      ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb);
 
   /* Efficiently convert pixels to scene linear colorspace at render time,
    * for OSL where the image texture cache contains original pixels. The
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
index 3595ca55a46..dbc8bf213af 100644
--- a/intern/cycles/scene/image.cpp
+++ b/intern/cycles/scene/image.cpp
@@ -576,13 +576,13 @@ bool ImageManager::file_load_image(Image *img, int texture_limit)
         pixels[i * 4 + 3] = one;
       }
     }
+  }
 
-    if (img->metadata.colorspace != u_colorspace_raw &&
-        img->metadata.colorspace != u_colorspace_srgb) {
-      /* Convert to scene linear. */
-      ColorSpaceManager::to_scene_linear(
-          img->metadata.colorspace, pixels, num_pixels, img->metadata.compress_as_srgb);
-    }
+  if (img->metadata.colorspace != u_colorspace_raw &&
+      img->metadata.colorspace != u_colorspace_srgb) {
+    /* Convert to scene linear. */
+    ColorSpaceManager::to_scene_linear(
+        img->metadata.colorspace, pixels, num_pixels, is_rgba, img->metadata.compress_as_srgb);
   }
 
   /* Make sure we don't have buggy values. */



More information about the Bf-blender-cvs mailing list