[Bf-blender-cvs] [f37864930d9] temp-eevee-next-cryptomatte: ImBuf: Optimize GPU memory by using 1 component format for grayscale images

Jeroen Bakker noreply at git.blender.org
Tue Aug 23 15:09:15 CEST 2022


Commit: f37864930d9fd90e477661279440218f35695728
Author: Jeroen Bakker
Date:   Tue Aug 23 14:26:01 2022 +0200
Branches: temp-eevee-next-cryptomatte
https://developer.blender.org/rBf37864930d9fd90e477661279440218f35695728

ImBuf: Optimize GPU memory by using 1 component format for grayscale images

This is done by checking the number of bitplanes from the image buffer.
We assume that for float buffer to use the same bitplanes as it was a
byte buffer.

Then, the data of the image buffer is packed at the start of the `rect` or
`float_rect` before upload.

**Statistics - einar.v004.blend **

Note that not all grayscale textures have been stored as BW images so the
amount of memory that can be reduced would be more.

Without patch
```
104 Textures - 3294.99 MB (3294.47 MB over 32x32), 37 RTs - 192.52 MB.
Avg. tex dimension: 2201.88x1253.51 (2283.53x2202.13 over 32x32)
464 Buffers - 25.01 MB total 1.24 MB IBs 23.50 MB VBs.
3512.52 MB - Grand total GPU buffer + texture load
```

Patch applied
```
104 Textures - 2917.66 MB (2917.14 MB over 32x32), 39 RTs - 215.45 MB.
Avg. tex dimension: 2221.38x1252.75 (2323.28x2253.47 over 32x32)
467 Buffers - 25.01 MB total 1.24 MB IBs 23.51 MB VBs.
3158.13 MB - Grand total GPU buffer + texture load.
```

Reviewed By: fclem

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

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

M	source/blender/blenkernel/BKE_pbvh_pixels.hh
M	source/blender/blenkernel/intern/image_gpu.cc
M	source/blender/editors/sculpt_paint/paint_image.cc
M	source/blender/editors/space_image/image_buttons.c
M	source/blender/imbuf/IMB_imbuf.h
M	source/blender/imbuf/intern/tiff.c
M	source/blender/imbuf/intern/util_gpu.c

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

diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh
index e73950e6299..ad8eca2b36f 100644
--- a/source/blender/blenkernel/BKE_pbvh_pixels.hh
+++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh
@@ -186,8 +186,14 @@ struct NodeData {
   {
     UDIMTilePixels *tile = find_tile_data(image_tile);
     if (tile && tile->flags.dirty) {
-      BKE_image_partial_update_mark_region(
-          &image, image_tile.image_tile, &image_buffer, &tile->dirty_region);
+      if (image_buffer.planes == 8) {
+        image_buffer.planes = 32;
+        BKE_image_partial_update_mark_full_update(&image);
+      }
+      else {
+        BKE_image_partial_update_mark_region(
+            &image, image_tile.image_tile, &image_buffer, &tile->dirty_region);
+      }
       tile->clear_dirty();
     }
   }
diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc
index 6506b40b603..08fdd715512 100644
--- a/source/blender/blenkernel/intern/image_gpu.cc
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -138,6 +138,8 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
   int arraywidth = 0, arrayheight = 0;
   ListBase boxes = {nullptr};
 
+  int planes = 0;
+
   LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
     ImageUser iuser;
     BKE_imageuser_default(&iuser);
@@ -164,6 +166,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
 
       BKE_image_release_ibuf(ima, ibuf, nullptr);
       BLI_addtail(&boxes, packtile);
+      planes = max_ii(planes, ibuf->planes);
     }
   }
 
@@ -195,9 +198,15 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
   }
 
   const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
+  const bool use_grayscale = planes <= 8;
   /* Create Texture without content. */
-  GPUTexture *tex = IMB_touch_gpu_texture(
-      ima->id.name + 2, main_ibuf, arraywidth, arrayheight, arraylayers, use_high_bitdepth);
+  GPUTexture *tex = IMB_touch_gpu_texture(ima->id.name + 2,
+                                          main_ibuf,
+                                          arraywidth,
+                                          arrayheight,
+                                          arraylayers,
+                                          use_high_bitdepth,
+                                          use_grayscale);
 
   /* Upload each tile one by one. */
   LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
@@ -223,6 +232,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
                                  tilelayer,
                                  UNPACK2(tilesize),
                                  use_high_bitdepth,
+                                 use_grayscale,
                                  store_premultiplied);
     }
 
diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc
index 24290fed323..5a6ac9463e2 100644
--- a/source/blender/editors/sculpt_paint/paint_image.cc
+++ b/source/blender/editors/sculpt_paint/paint_image.cc
@@ -158,6 +158,16 @@ void imapaint_image_update(
                                             imapaintpartial.dirty_region.xmax,
                                             imapaintpartial.dirty_region.ymax);
 
+  /* When buffer is partial updated the planes should be set to a larger value than 8. This will
+   * make sure that partial updating is working but uses more GPU memory as the gpu texture will
+   * have 4 channels. When so the whole texture needs to be reuploaded to the GPU using the new
+   * texture format.*/
+  if (ibuf != nullptr && ibuf->planes == 8) {
+    ibuf->planes = 32;
+    BKE_image_partial_update_mark_full_update(image);
+    return;
+  }
+
   /* TODO: should set_tpage create ->rect? */
   if (texpaint || (sima && sima->lock)) {
     const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region);
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index cc6bf644447..bc367a99d6b 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -1212,8 +1212,8 @@ void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *i
       ofs += BLI_strncpy_rlen(str + ofs, TIP_(" + Z"), len - ofs);
     }
 
-    eGPUTextureFormat texture_format = IMB_gpu_get_texture_format(ibuf,
-                                                                  ima->flag & IMA_HIGH_BITDEPTH);
+    eGPUTextureFormat texture_format = IMB_gpu_get_texture_format(
+        ibuf, ima->flag & IMA_HIGH_BITDEPTH, ibuf->planes >= 8);
     const char *texture_format_description = GPU_texture_format_description(texture_format);
     ofs += BLI_snprintf_rlen(str + ofs, len - ofs, TIP_(",  %s"), texture_format_description);
 
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 3a770c9a2b7..6881916d1d2 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -890,14 +890,22 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
                                    bool use_high_bitdepth,
                                    bool use_premult);
 
-eGPUTextureFormat IMB_gpu_get_texture_format(const struct ImBuf *ibuf, bool high_bitdepth);
+eGPUTextureFormat IMB_gpu_get_texture_format(const struct ImBuf *ibuf,
+                                             bool high_bitdepth,
+                                             bool use_grayscale);
 
 /**
  * The `ibuf` is only here to detect the storage type. The produced texture will have undefined
  * content. It will need to be populated by using #IMB_update_gpu_texture_sub().
  */
-GPUTexture *IMB_touch_gpu_texture(
-    const char *name, struct ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth);
+GPUTexture *IMB_touch_gpu_texture(const char *name,
+                                  struct ImBuf *ibuf,
+                                  int w,
+                                  int h,
+                                  int layers,
+                                  bool use_high_bitdepth,
+                                  bool use_grayscale);
+
 /**
  * Will update a #GPUTexture using the content of the #ImBuf. Only one layer will be updated.
  * Will resize the ibuf if needed.
@@ -911,6 +919,7 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex,
                                 int w,
                                 int h,
                                 bool use_high_bitdepth,
+                                bool use_grayscale,
                                 bool use_premult);
 
 /**
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 2f13ef409e3..dae6ef49c6d 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -460,7 +460,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
         scanline_contig_16bit(tmpibuf->rect_float + ib_offset, sbuf, ibuf->x, spp);
       }
     }
-    /* separate channels: RRRGGGBBB */
+    /* Separate channels: RRRGGGBBB. */
   }
   else if (config == PLANARCONFIG_SEPARATE) {
 
@@ -574,7 +574,7 @@ ImBuf *imb_loadtiff(const unsigned char *mem,
   TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height);
   TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp);
 
-  ib_depth = (spp == 3) ? 24 : 32;
+  ib_depth = spp * 8;
 
   ibuf = IMB_allocImBuf(width, height, ib_depth, 0);
   if (ibuf) {
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 727704e27e8..b606af99ad0 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -14,6 +14,7 @@
 #include "BKE_global.h"
 
 #include "GPU_capabilities.h"
+#include "GPU_state.h"
 #include "GPU_texture.h"
 
 #include "IMB_colormanagement.h"
@@ -22,39 +23,62 @@
 
 /* gpu ibuf utils */
 
+static bool imb_is_grayscale_texture_format_compatible(const ImBuf *ibuf)
+{
+  if (ibuf->planes > 8) {
+    return false;
+  }
+  /* Only imbufs with colorspace that do not modify the chrominance of the texture data relative
+   * to the scene color space can be uploaded as single channel textures. */
+  if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
+      IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+      IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+    return true;
+  };
+  return false;
+}
+
 static void imb_gpu_get_format(const ImBuf *ibuf,
                                bool high_bitdepth,
+                               bool use_grayscale,
                                eGPUDataFormat *r_data_format,
                                eGPUTextureFormat *r_texture_format)
 {
   const bool float_rect = (ibuf->rect_float != NULL);
+  const bool is_grayscale = use_grayscale && imb_is_grayscale_texture_format_compatible(ibuf);
 
   if (float_rect) {
     /* Float. */
     const bool use_high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
     *r_data_format = GPU_DATA_FLOAT;
-    *r_texture_format = use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
+    *r_texture_format = is_grayscale ? (use_high_bitdepth ? GPU_R32F : GPU_R16F) :
+                                       (use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F);
   }
   else {
     if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
         IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
       /* Non-color data or scene linear, just store buffer as is. */
       *r_data_format = GPU_DATA_UBYTE;
-      *r_texture_format = GPU_RGBA8;
+      *r_texture_format = (is_grayscale) ? GPU_R8 : GPU_RGBA8;
     }
     else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
       /* sRGB, store as byte texture that the GPU can decode directly. */
-      *r_data_format = GPU_DATA_UBYTE;
-      *r_texture_format = GPU_SRGB8_A8;
+      *r_data_format = (is_grayscale) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
+      *r_texture_format = (is_grayscale) ? GPU_R16F : GPU_SRGB8_A8;
     }
     else {
       /* Other colorspace, stor

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list