[Bf-blender-cvs] [44258b5ad07] master: Undo: Improve image undo performance

Alex Parker noreply at git.blender.org
Mon Jul 25 08:14:33 CEST 2022


Commit: 44258b5ad0737140d7d1026cc540e3f94ea05566
Author: Alex Parker
Date:   Mon Jul 25 07:56:17 2022 +0200
Branches: master
https://developer.blender.org/rB44258b5ad0737140d7d1026cc540e3f94ea05566

Undo: Improve image undo performance

When texture painting a lot of time is spent in ED_image_paint_tile_find.
This fixes stores the PaintTiles in a blender::Map making ED_image_paint_tile_find an O(1) rather than O(n) operation.

When using threading the locking should happen during read as well,
still this gives a boost in performance as the read is now much faster.

Reviewed By: jbakker

Maniphest Tasks: T99546

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

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

M	source/blender/editors/include/ED_paint.h
M	source/blender/editors/sculpt_paint/paint_image.cc
M	source/blender/editors/sculpt_paint/paint_image_2d.c
M	source/blender/editors/sculpt_paint/paint_image_proj.c
M	source/blender/editors/sculpt_paint/sculpt_paint_image.cc
M	source/blender/editors/space_image/CMakeLists.txt
R078	source/blender/editors/space_image/image_undo.c	source/blender/editors/space_image/image_undo.cc

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

diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index ba5834fd508..048424cdee1 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -22,6 +22,7 @@ struct UndoType;
 struct bContext;
 struct wmKeyConfig;
 struct wmOperator;
+typedef struct PaintTileMap PaintTileMap;
 
 /* paint_ops.c */
 
@@ -76,7 +77,7 @@ void ED_image_undo_restore(struct UndoStep *us);
 /** Export for ED_undo_sys. */
 void ED_image_undosys_type(struct UndoType *ut);
 
-void *ED_image_paint_tile_find(struct ListBase *paint_tiles,
+void *ED_image_paint_tile_find(PaintTileMap *paint_tile_map,
                                struct Image *image,
                                struct ImBuf *ibuf,
                                struct ImageUser *iuser,
@@ -84,7 +85,7 @@ void *ED_image_paint_tile_find(struct ListBase *paint_tiles,
                                int y_tile,
                                unsigned short **r_mask,
                                bool validate);
-void *ED_image_paint_tile_push(struct ListBase *paint_tiles,
+void *ED_image_paint_tile_push(PaintTileMap *paint_tile_map,
                                struct Image *image,
                                struct ImBuf *ibuf,
                                struct ImBuf **tmpibuf,
@@ -98,7 +99,7 @@ void *ED_image_paint_tile_push(struct ListBase *paint_tiles,
 void ED_image_paint_tile_lock_init(void);
 void ED_image_paint_tile_lock_end(void);
 
-struct ListBase *ED_image_paint_tile_list_get(void);
+struct PaintTileMap *ED_image_paint_tile_map_get(void);
 
 #define ED_IMAGE_UNDO_TILE_BITS 6
 #define ED_IMAGE_UNDO_TILE_SIZE (1 << ED_IMAGE_UNDO_TILE_BITS)
diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc
index 6ed43fe6403..24290fed323 100644
--- a/source/blender/editors/sculpt_paint/paint_image.cc
+++ b/source/blender/editors/sculpt_paint/paint_image.cc
@@ -125,7 +125,7 @@ void ED_imapaint_dirty_region(
 
   imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
 
-  ListBase *undo_tiles = ED_image_paint_tile_list_get();
+  PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
 
   for (ty = tiley; ty <= tileh; ty++) {
     for (tx = tilex; tx <= tilew; tx++) {
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index fae2e6863fa..5df65e596b9 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1196,7 +1196,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
   ImBuf tmpbuf;
   IMB_initImBuf(&tmpbuf, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, 0);
 
-  ListBase *undo_tiles = ED_image_paint_tile_list_get();
+  PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
 
   for (int ty = tiley; ty <= tileh; ty++) {
     for (int tx = tilex; tx <= tilew; tx++) {
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 50480b8aef0..9449cc6eb8d 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -1813,7 +1813,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
   }
 
   if (generate_tile) {
-    ListBase *undo_tiles = ED_image_paint_tile_list_get();
+    struct PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
     volatile void *undorect;
     if (tinf->masked) {
       undorect = ED_image_paint_tile_push(undo_tiles,
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index 975a8f21aaf..f51a603ee5d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -383,7 +383,7 @@ static void push_undo(const NodeData &node_data,
       continue;
     }
     int tilex, tiley, tilew, tileh;
-    ListBase *undo_tiles = ED_image_paint_tile_list_get();
+    PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
     undo_region_tiles(&image_buffer,
                       tile_undo.region.xmin,
                       tile_undo.region.ymin,
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 39fb41245bf..c6a1a6a77b4 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -28,7 +28,7 @@ set(SRC
   image_edit.c
   image_ops.c
   image_sequence.c
-  image_undo.c
+  image_undo.cc
   space_image.c
 
   image_intern.h
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.cc
similarity index 78%
rename from source/blender/editors/space_image/image_undo.c
rename to source/blender/editors/space_image/image_undo.cc
index a7a8bde1115..986265afee0 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.cc
@@ -25,6 +25,7 @@
 #include "BLI_math.h"
 #include "BLI_threads.h"
 #include "BLI_utildefines.h"
+#include "BLI_map.hh"
 
 #include "DNA_image_types.h"
 #include "DNA_object_types.h"
@@ -82,14 +83,31 @@ void ED_image_paint_tile_lock_end(void)
  *
  * \{ */
 
-static ImBuf *imbuf_alloc_temp_tile(void)
+static ImBuf *imbuf_alloc_temp_tile()
 {
   return IMB_allocImBuf(
       ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, IB_rectfloat | IB_rect);
 }
 
-typedef struct PaintTile {
-  struct PaintTile *next, *prev;
+struct PaintTileKey {
+  int x_tile, y_tile;
+  Image *image;
+  ImBuf *ibuf;
+  /* Copied from iuser.tile in PaintTile. */
+  int iuser_tile;
+
+  uint64_t hash() const
+  {
+    return blender::get_default_hash_4(x_tile, y_tile, image, ibuf);
+  }
+  bool operator==(const PaintTileKey &other) const
+  {
+    return x_tile == other.x_tile && y_tile == other.y_tile && image == other.image &&
+           ibuf == other.ibuf && iuser_tile == other.iuser_tile;
+  }
+};
+
+struct PaintTile {
   Image *image;
   ImBuf *ibuf;
   /* For 2D image painting the ImageUser uses most of the values.
@@ -99,14 +117,14 @@ typedef struct PaintTile {
   ImageUser iuser;
   union {
     float *fp;
-    uint *uint;
+    uint32_t *uint;
     void *pt;
   } rect;
-  ushort *mask;
+  uint16_t *mask;
   bool valid;
   bool use_float;
   int x_tile, y_tile;
-} PaintTile;
+};
 
 static void ptile_free(PaintTile *ptile)
 {
@@ -119,23 +137,25 @@ static void ptile_free(PaintTile *ptile)
   MEM_freeN(ptile);
 }
 
-static void ptile_free_list(ListBase *paint_tiles)
-{
-  for (PaintTile *ptile = paint_tiles->first, *ptile_next; ptile; ptile = ptile_next) {
-    ptile_next = ptile->next;
-    ptile_free(ptile);
+struct PaintTileMap {
+  blender::Map<PaintTileKey, PaintTile *> map;
+
+  ~PaintTileMap()
+  {
+    for (PaintTile *ptile : map.values()) {
+      ptile_free(ptile);
+    }
   }
-  BLI_listbase_clear(paint_tiles);
-}
+};
 
-static void ptile_invalidate_list(ListBase *paint_tiles)
+static void ptile_invalidate_map(PaintTileMap *paint_tile_map)
 {
-  LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
+  for (PaintTile *ptile : paint_tile_map->map.values()) {
     ptile->valid = false;
   }
 }
 
-void *ED_image_paint_tile_find(ListBase *paint_tiles,
+void *ED_image_paint_tile_find(PaintTileMap *paint_tile_map,
                                Image *image,
                                ImBuf *ibuf,
                                ImageUser *iuser,
@@ -144,28 +164,32 @@ void *ED_image_paint_tile_find(ListBase *paint_tiles,
                                ushort **r_mask,
                                bool validate)
 {
-  LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
-    if (ptile->x_tile == x_tile && ptile->y_tile == y_tile) {
-      if (ptile->image == image && ptile->ibuf == ibuf && ptile->iuser.tile == iuser->tile) {
-        if (r_mask) {
-          /* allocate mask if requested. */
-          if (!ptile->mask) {
-            ptile->mask = MEM_callocN(sizeof(ushort) * square_i(ED_IMAGE_UNDO_TILE_SIZE),
-                                      "UndoImageTile.mask");
-          }
-          *r_mask = ptile->mask;
-        }
-        if (validate) {
-          ptile->valid = true;
-        }
-        return ptile->rect.pt;
-      }
+  PaintTileKey key;
+  key.ibuf = ibuf;
+  key.image = image;
+  key.iuser_tile = iuser->tile;
+  key.x_tile = x_tile;
+  key.y_tile = y_tile;
+  PaintTile **pptile = paint_tile_map->map.lookup_ptr(key);
+  if (pptile == nullptr) {
+    return nullptr;
+  }
+  PaintTile *ptile = *pptile;
+  if (r_mask) {
+    /* allocate mask if requested. */
+    if (!ptile->mask) {
+      ptile->mask = static_cast<uint16_t *>(MEM_callocN(sizeof(uint16_t) * square_i(ED_IMAGE_UNDO_TILE_SIZE),
+                                          "UndoImageTile.mask"));
     }
+    *r_mask = ptile->mask;
+  }
+  if (validate) {
+    ptile->valid = true;
   }
-  return NULL;
+  return ptile->rect.pt;
 }
 
-void *ED_image_paint_tile_push(ListBase *paint_tiles,
+void *ED_image_paint_tile_push(PaintTileMap *paint_tile_map,
                                Image *image,
                                ImBuf *ibuf,
                                ImBuf **tmpibuf,
@@ -177,37 +201,43 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
                                bool use_thread_lock,
                                bool find_prev)
 {
-  const bool has_float = (ibuf->rect_float != NULL);
+  if (use_thread_lock) {
+    BLI_spin_lock(&paint_tiles_lock);
+  }
+  const bool has_float = (ibuf->rect_float != nullptr);
 
   /* check if tile is already pushed */
 
   /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
   if (find_prev) {
     void *data = ED_image_paint_tile_find(
-        paint_tiles, image, ibuf, iuser, x_tile, y_tile, r_mask, true);
+        paint_tile_map, image, ibuf, iuser, x_tile, y_tile, r_mask, true);
     if (data) {
+      if (use_thread_lock) {
+        BLI_spin_unlock(&paint_tiles_lock);
+      }
       return data;
     }
   }
 
-  if (*tmp

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list