Commit: 9d8fb80f218f05f743943a289e2aad579e709058
Author: Brecht Van Lommel
Date:   Fri Jun 3 14:13:10 2022 +0200
Branches: master
https://developer.blender.org/rB9d8fb80f218f05f743943a289e2aad579e709058

Eevee/Workbench: store 8 bit image textures as half float for some color spaces

Same as in Cycles, this is needed for some color space conversions that don't
compress well to byte sRGB, like for example Filmic sRGB.

Ref T68926

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

M       source/blender/blenkernel/intern/image_gpu.cc
M       source/blender/imbuf/IMB_colormanagement.h
M       source/blender/imbuf/intern/colormanagement.c
M       source/blender/imbuf/intern/util_gpu.c

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

diff --git a/source/blender/blenkernel/intern/image_gpu.cc 
b/source/blender/blenkernel/intern/image_gpu.cc
index bed79a318e8..6edb9e1b24c 100644
--- a/source/blender/blenkernel/intern/image_gpu.cc
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -718,12 +718,31 @@ static void gpu_texture_update_from_ibuf(
   int tex_offset = ibuf->channels * (y * ibuf->x + x);
 
   const bool store_premultiplied = 
BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
-  if (rect_float == nullptr) {
-    /* Byte pixels. */
-    if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
-      const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(
-          ibuf->rect_colorspace);
+  if (rect_float) {
+    /* Float image is already in scene linear colorspace or non-color data by
+     * convention, no colorspace conversion needed. But we do require 4 
channels
+     * currently. */
+    if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+      rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
+      if (rect_float == nullptr) {
+        return;
+      }
 
+      tex_stride = w;
+      tex_offset = 0;
+
+      IMB_colormanagement_imbuf_to_float_texture(
+          rect_float, x, y, w, h, ibuf, store_premultiplied);
+    }
+  }
+  else {
+    /* Byte image is in original colorspace from the file, and may need 
conversion. */
+    if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
+        IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+      /* Non-color data, just store buffer as is. */
+    }
+    else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
+      /* sRGB or scene linear, store as byte texture that the GPU can decode 
directly. */
       rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__);
       if (rect == nullptr) {
         return;
@@ -734,13 +753,10 @@ static void gpu_texture_update_from_ibuf(
 
       /* Convert to scene linear with sRGB compression, and premultiplied for
        * correct texture interpolation. */
-      IMB_colormanagement_imbuf_to_byte_texture(
-          rect, x, y, w, h, ibuf, compress_as_srgb, store_premultiplied);
+      IMB_colormanagement_imbuf_to_byte_texture(rect, x, y, w, h, ibuf, 
store_premultiplied);
     }
-  }
-  else {
-    /* Float pixels. */
-    if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+    else {
+      /* Other colorspace, store as float texture to avoid precision loss. */
       rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
       if (rect_float == nullptr) {
         return;
diff --git a/source/blender/imbuf/IMB_colormanagement.h 
b/source/blender/imbuf/IMB_colormanagement.h
index 75159e186e9..2f0d2f9b449 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -181,7 +181,6 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned 
char *out_buffer,
                                                int width,
                                                int height,
                                                const struct ImBuf *ibuf,
-                                               bool compress_as_srgb,
                                                bool store_premultiplied);
 void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
                                                 int offset_x,
diff --git a/source/blender/imbuf/intern/colormanagement.c 
b/source/blender/imbuf/intern/colormanagement.c
index 0a85b31ef7b..33873b5daa7 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -2211,21 +2211,14 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned 
char *out_buffer,
                                                const int width,
                                                const int height,
                                                const struct ImBuf *ibuf,
-                                               const bool compress_as_srgb,
                                                const bool store_premultiplied)
 {
-  /* Convert byte buffer for texture storage on the GPU. These have builtin
-   * support for converting sRGB to linear, which allows us to store textures
-   * without precision or performance loss at minimal memory usage. */
+  /* Byte buffer storage, only for sRGB and data texture since other
+   * color space conversions can't be done on the GPU. */
   BLI_assert(ibuf->rect && ibuf->rect_float == NULL);
+  BLI_assert(IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+             IMB_colormanagement_space_is_data(ibuf->rect_colorspace));
 
-  OCIO_ConstCPUProcessorRcPtr *processor = NULL;
-  if (compress_as_srgb && ibuf->rect_colorspace &&
-      !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
-    processor = 
colorspace_to_scene_linear_cpu_processor(ibuf->rect_colorspace);
-  }
-
-  /* TODO(brecht): make this multi-threaded, or at least process in batches. */
   const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
   const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && 
store_premultiplied;
 
@@ -2235,20 +2228,7 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned 
char *out_buffer,
     const unsigned char *in = in_buffer + in_offset * 4;
     unsigned char *out = out_buffer + out_offset * 4;
 
-    if (processor != NULL) {
-      /* Convert to scene linear, to sRGB and premultiply. */
-      for (int x = 0; x < width; x++, in += 4, out += 4) {
-        float pixel[4];
-        rgba_uchar_to_float(pixel, in);
-        OCIO_cpuProcessorApplyRGB(processor, pixel);
-        linearrgb_to_srgb_v3_v3(pixel, pixel);
-        if (use_premultiply) {
-          mul_v3_fl(pixel, pixel[3]);
-        }
-        rgba_float_to_uchar(out, pixel);
-      }
-    }
-    else if (use_premultiply) {
+    if (use_premultiply) {
       /* Premultiply only. */
       for (int x = 0; x < width; x++, in += 4, out += 4) {
         out[0] = (in[0] * in[3]) >> 8;
@@ -2279,43 +2259,80 @@ void IMB_colormanagement_imbuf_to_float_texture(float 
*out_buffer,
 {
   /* Float texture are stored in scene linear color space, with premultiplied
    * alpha depending on the image alpha mode. */
-  const float *in_buffer = ibuf->rect_float;
-  const int in_channels = ibuf->channels;
-  const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && 
!store_premultiplied;
-
-  for (int y = 0; y < height; y++) {
-    const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
-    const size_t out_offset = y * width;
-    const float *in = in_buffer + in_offset * in_channels;
-    float *out = out_buffer + out_offset * 4;
-
-    if (in_channels == 1) {
-      /* Copy single channel. */
-      for (int x = 0; x < width; x++, in += 1, out += 4) {
-        out[0] = in[0];
-        out[1] = in[0];
-        out[2] = in[0];
-        out[3] = in[0];
+  if (ibuf->rect_float) {
+    /* Float source buffer. */
+    const float *in_buffer = ibuf->rect_float;
+    const int in_channels = ibuf->channels;
+    const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && 
!store_premultiplied;
+
+    for (int y = 0; y < height; y++) {
+      const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+      const size_t out_offset = y * width;
+      const float *in = in_buffer + in_offset * in_channels;
+      float *out = out_buffer + out_offset * 4;
+
+      if (in_channels == 1) {
+        /* Copy single channel. */
+        for (int x = 0; x < width; x++, in += 1, out += 4) {
+          out[0] = in[0];
+          out[1] = in[0];
+          out[2] = in[0];
+          out[3] = in[0];
+        }
       }
-    }
-    else if (in_channels == 3) {
-      /* Copy RGB. */
-      for (int x = 0; x < width; x++, in += 3, out += 4) {
-        out[0] = in[0];
-        out[1] = in[1];
-        out[2] = in[2];
-        out[3] = 1.0f;
+      else if (in_channels == 3) {
+        /* Copy RGB. */
+        for (int x = 0; x < width; x++, in += 3, out += 4) {
+          out[0] = in[0];
+          out[1] = in[1];
+          out[2] = in[2];
+          out[3] = 1.0f;
+        }
       }
-    }
-    else if (in_channels == 4) {
-      /* Copy or convert RGBA. */
-      if (use_unpremultiply) {
-        for (int x = 0; x < width; x++, in += 4, out += 4) {
-          premul_to_straight_v4_v4(out, in);
+      else if (in_channels == 4) {
+        /* Copy or convert RGBA. */
+        if (use_unpremultiply) {
+          for (int x = 0; x < width; x++, in += 4, out += 4) {
+            premul_to_straight_v4_v4(out, in);
+          }
+        }
+        else {
+          memcpy(out, in, sizeof(float[4]) * width);
         }
       }
-      else {
-        memcpy(out, in, sizeof(float[4]) * width);
+    }
+  }
+  else {
+    /* Byte source buffer. */
+    const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
+    const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && 
store_premultiplied;
+
+    /* TODO(brecht): make this multi-threaded, or at least process in batches. 
*/
+    OCIO_ConstCPUProcessorRcPtr *processor = (ibuf->rect_colorspace) ?
+                                                 
colorspace_to_scene_linear_cpu_processor(
+                                                     ibuf->rect_colorspace) :
+                                                 NULL;
+
+    for (int y = 0; y < height; y++) {
+      const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+      const size_t out_offset = y * width;
+      const unsigned char *in = in_buffer + in_offset * 4;
+      float *out = out_buffer + out_offset * 4;
+
+      /* Convert to scene linear, to sRGB and premultiply. */
+      for (int x = 0; x < width; x++, in += 4, out += 4) {
+        float pixel[4];
+        rgba_uchar_to_float(pixel, in);
+        if (processor) {
+          OCIO_cpuProcessorApplyRGB(processor, pixel);
+        }
+        else {
+          srgb_to_linearrgb_v3_v3(pixel, pixel);
+        }
+        if (use_premultiply) {
+          mul_v3_fl(pixel, pixel[3]);
+        }
+        copy_v4_v4(out, pixel);
       }
     }
   }
diff --git a/source/blender/imbuf/intern/util_gpu.c 
b/source/blender/imbuf/intern/util_gpu.c
index 

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to