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. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
