UI: Use a map for block name lookups

Use a map to speed up search for UI block names.
Time to redraw the node editor was decreased from
around 75-120ms to 40-70ms in a tree with many
Geometry Nodes.

Differential Revision: https://developer.blender.org/D13225
This commit is contained in:
Erik Abrahamsson 2021-11-15 17:10:53 +01:00
parent 55c82d8380
commit 0129178376
Notes: blender-bot 2023-02-14 10:14:07 +01:00
Referenced by issue #93523, Not freed memory blocks in Menu Search
9 changed files with 35 additions and 14 deletions

View File

@ -731,8 +731,8 @@ bool UI_block_is_search_only(const uiBlock *block);
void UI_block_set_search_only(uiBlock *block, bool search_only);
void UI_block_free(const struct bContext *C, uiBlock *block);
void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
void UI_blocklist_free_inactive(const struct bContext *C, struct ListBase *lb);
void UI_blocklist_free(const struct bContext *C, struct ARegion *region);
void UI_blocklist_free_inactive(const struct bContext *C, struct ARegion *region);
void UI_screen_free_active_but(const struct bContext *C, struct bScreen *screen);
void UI_block_region_set(uiBlock *block, struct ARegion *region);

View File

@ -37,6 +37,7 @@
#include "DNA_workspace_types.h"
#include "BLI_alloca.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
@ -3521,22 +3522,35 @@ void UI_blocklist_draw(const bContext *C, const ListBase *lb)
}
/* can be called with C==NULL */
void UI_blocklist_free(const bContext *C, ListBase *lb)
void UI_blocklist_free(const bContext *C, ARegion *region)
{
ListBase *lb = &region->uiblocks;
uiBlock *block;
while ((block = BLI_pophead(lb))) {
UI_block_free(C, block);
}
if (region->runtime.block_name_map != NULL) {
BLI_ghash_free(region->runtime.block_name_map, NULL, NULL);
region->runtime.block_name_map = NULL;
}
}
void UI_blocklist_free_inactive(const bContext *C, ListBase *lb)
void UI_blocklist_free_inactive(const bContext *C, ARegion *region)
{
ListBase *lb = &region->uiblocks;
LISTBASE_FOREACH_MUTABLE (uiBlock *, block, lb) {
if (!block->handle) {
if (block->active) {
block->active = false;
}
else {
if (region->runtime.block_name_map != NULL) {
uiBlock *b = BLI_ghash_lookup(region->runtime.block_name_map, block->name);
if (b == block) {
BLI_ghash_remove(region->runtime.block_name_map, b->name, NULL, NULL);
}
}
BLI_remlink(lb, block);
UI_block_free(C, block);
}
@ -3552,7 +3566,10 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
/* each listbase only has one block with this name, free block
* if is already there so it can be rebuilt from scratch */
if (lb) {
oldblock = BLI_findstring(lb, block->name, offsetof(uiBlock, name));
if (region->runtime.block_name_map == NULL) {
region->runtime.block_name_map = BLI_ghash_str_new(__func__);
}
oldblock = (uiBlock *)BLI_ghash_lookup(region->runtime.block_name_map, block->name);
if (oldblock) {
oldblock->active = false;
@ -3562,6 +3579,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
/* at the beginning of the list! for dynamical menus/blocks */
BLI_addhead(lb, block);
BLI_ghash_reinsert(region->runtime.block_name_map, block->name, block, NULL, NULL);
}
block->oldblock = oldblock;

View File

@ -11340,8 +11340,7 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
return;
}
UI_blocklist_free(C, &region->uiblocks);
UI_blocklist_free(C, region);
bScreen *screen = CTX_wm_screen(C);
if (screen == NULL) {
return;

View File

@ -743,7 +743,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
if (block_old) {
block->oldblock = block_old;
UI_block_update_from_old(C, block);
UI_blocklist_free_inactive(C, &region->uiblocks);
UI_blocklist_free_inactive(C, region);
}
/* checks which buttons are visible, sets flags to prevent draw (do after region init) */

View File

@ -787,12 +787,14 @@ static MenuSearch_Data *menu_items_from_ui_create(
}
if (region) {
BLI_ghash_remove(region->runtime.block_name_map, sub_block->name, NULL, NULL);
BLI_remlink(&region->uiblocks, sub_block);
}
UI_block_free(nullptr, sub_block);
}
}
if (region) {
BLI_ghash_remove(region->runtime.block_name_map, block->name, NULL, NULL);
BLI_remlink(&region->uiblocks, block);
}
UI_block_free(nullptr, block);

View File

@ -594,7 +594,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
memset(&region->drawrct, 0, sizeof(region->drawrct));
UI_blocklist_free_inactive(C, &region->uiblocks);
UI_blocklist_free_inactive(C, region);
if (area) {
const bScreen *screen = WM_window_get_active_screen(win);
@ -1985,7 +1985,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
}
else {
/* prevent uiblocks to run */
UI_blocklist_free(NULL, &region->uiblocks);
UI_blocklist_free(NULL, region);
}
/* Some AZones use View2D data which is only updated in region init, so call that first! */
@ -3323,7 +3323,7 @@ bool ED_region_property_search(const bContext *C,
}
/* Free the panels and blocks, as they are only used for search. */
UI_blocklist_free(C, &region->uiblocks);
UI_blocklist_free(C, region);
UI_panels_free_instanced(C, region);
BKE_area_region_panels_free(&region->panels);

View File

@ -1495,8 +1495,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
* switching screens with tooltip open because region and tooltip
* are no longer in the same screen */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
UI_blocklist_free(C, &region->uiblocks);
UI_blocklist_free(C, region);
if (region->regiontimer) {
WM_event_remove_timer(wm, NULL, region->regiontimer);
region->regiontimer = NULL;

View File

@ -445,7 +445,7 @@ static void property_search_all_tabs(const bContext *C,
i,
property_search_for_context(C, region_copy, &sbuts_copy));
UI_blocklist_free(C, &region_copy->uiblocks);
UI_blocklist_free(C, region_copy);
}
BKE_area_region_free(area_copy.type, region_copy);

View File

@ -458,6 +458,9 @@ typedef struct ARegion_Runtime {
/* The offset needed to not overlap with window scrollbars. Only used by HUD regions for now. */
int offset_x, offset_y;
/* Maps uiBlock->name to uiBlock for faster lookups. */
struct GHash *block_name_map;
} ARegion_Runtime;
typedef struct ARegion {