UI: Use vector instead of linked lists for context store

Duplicating context lists took a measurable amount of time when drawing
large node trees in the node editor. Instead of using a linked list of
entries, which results in many small allocations, use a vector. Also,
use std::string and StringRefNull instead of char buffers and pointers.
This commit is contained in:
2022-12-18 19:13:15 -06:00
parent d59f6ffdcb
commit 7d7e90ca68
3 changed files with 53 additions and 66 deletions

View File

@@ -16,6 +16,11 @@
#include "DNA_object_enums.h" #include "DNA_object_enums.h"
#include "RNA_types.h" #include "RNA_types.h"
#ifdef __cplusplus
# include "BLI_string_ref.hh"
# include "BLI_vector.hh"
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -84,19 +89,22 @@ typedef int /*eContextResult*/ (*bContextDataCallback)(const bContext *C,
const char *member, const char *member,
bContextDataResult *result); bContextDataResult *result);
typedef struct bContextStoreEntry { #ifdef __cplusplus
struct bContextStoreEntry *next, *prev;
char name[128]; struct bContextStoreEntry {
std::string name;
PointerRNA ptr; PointerRNA ptr;
} bContextStoreEntry; };
typedef struct bContextStore { struct bContextStore {
struct bContextStore *next, *prev; bContextStore *next = nullptr;
bContextStore *prev = nullptr;
ListBase entries; blender::Vector<bContextStoreEntry> entries;
bool used; bool used = false;
} bContextStore; };
#endif
/* for the context's rna mode enum /* for the context's rna mode enum
* keep aligned with data_mode_strings in context.cc */ * keep aligned with data_mode_strings in context.cc */
@@ -132,18 +140,23 @@ void CTX_free(bContext *C);
bContext *CTX_copy(const bContext *C); bContext *CTX_copy(const bContext *C);
#ifdef __cplusplus
/* Stored Context */ /* Stored Context */
bContextStore *CTX_store_add(ListBase *contexts, const char *name, const PointerRNA *ptr); bContextStore *CTX_store_add(ListBase *contexts,
blender::StringRefNull name,
const PointerRNA *ptr);
bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context); bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context);
bContextStore *CTX_store_get(bContext *C); bContextStore *CTX_store_get(bContext *C);
void CTX_store_set(bContext *C, bContextStore *store); void CTX_store_set(bContext *C, bContextStore *store);
const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store, const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store,
const char *name, blender::StringRefNull name,
const StructRNA *type CPP_ARG_DEFAULT(nullptr)); const StructRNA *type = nullptr);
bContextStore *CTX_store_copy(bContextStore *store); bContextStore *CTX_store_copy(const bContextStore *store);
void CTX_store_free(bContextStore *store); void CTX_store_free(bContextStore *store);
void CTX_store_free_list(ListBase *contexts);
#endif
/* need to store if python is initialized or not */ /* need to store if python is initialized or not */
bool CTX_py_init_get(bContext *C); bool CTX_py_init_get(bContext *C);

View File

@@ -126,7 +126,9 @@ void CTX_free(bContext *C)
/* store */ /* store */
bContextStore *CTX_store_add(ListBase *contexts, const char *name, const PointerRNA *ptr) bContextStore *CTX_store_add(ListBase *contexts,
const blender::StringRefNull name,
const PointerRNA *ptr)
{ {
/* ensure we have a context to put the entry in, if it was already used /* ensure we have a context to put the entry in, if it was already used
* we have to copy the context to ensure */ * we have to copy the context to ensure */
@@ -134,23 +136,16 @@ bContextStore *CTX_store_add(ListBase *contexts, const char *name, const Pointer
if (!ctx || ctx->used) { if (!ctx || ctx->used) {
if (ctx) { if (ctx) {
bContextStore *lastctx = ctx; ctx = MEM_new<bContextStore>(__func__, *ctx);
ctx = MEM_new<bContextStore>(__func__);
*ctx = *lastctx;
BLI_duplicatelist(&ctx->entries, &lastctx->entries);
} }
else { else {
ctx = MEM_cnew<bContextStore>(__func__); ctx = MEM_new<bContextStore>(__func__);
} }
BLI_addtail(contexts, ctx); BLI_addtail(contexts, ctx);
} }
bContextStoreEntry *entry = MEM_cnew<bContextStoreEntry>(__func__); ctx->entries.append(bContextStoreEntry{name, *ptr});
BLI_strncpy(entry->name, name, sizeof(entry->name));
entry->ptr = *ptr;
BLI_addtail(&ctx->entries, entry);
return ctx; return ctx;
} }
@@ -163,22 +158,17 @@ bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context)
if (!ctx || ctx->used) { if (!ctx || ctx->used) {
if (ctx) { if (ctx) {
bContextStore *lastctx = ctx; ctx = MEM_new<bContextStore>(__func__, *ctx);
ctx = MEM_new<bContextStore>(__func__);
*ctx = *lastctx;
BLI_duplicatelist(&ctx->entries, &lastctx->entries);
} }
else { else {
ctx = MEM_cnew<bContextStore>(__func__); ctx = MEM_new<bContextStore>(__func__);
} }
BLI_addtail(contexts, ctx); BLI_addtail(contexts, ctx);
} }
LISTBASE_FOREACH (bContextStoreEntry *, tentry, &context->entries) { for (const bContextStoreEntry &src_entry : context->entries) {
bContextStoreEntry *entry = MEM_cnew<bContextStoreEntry>(__func__); ctx->entries.append(src_entry);
*entry = *tentry;
BLI_addtail(&ctx->entries, entry);
} }
return ctx; return ctx;
@@ -195,42 +185,27 @@ void CTX_store_set(bContext *C, bContextStore *store)
} }
const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store, const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store,
const char *name, const blender::StringRefNull name,
const StructRNA *type) const StructRNA *type)
{ {
bContextStoreEntry *entry = static_cast<bContextStoreEntry *>( for (auto entry = store->entries.rbegin(); entry != store->entries.rend(); ++entry) {
BLI_rfindstring(&store->entries, name, offsetof(bContextStoreEntry, name))); if (entry->name == name) {
if (!entry) { if (type && RNA_struct_is_a(entry->ptr.type, type)) {
return nullptr; return &entry->ptr;
}
}
} }
return nullptr;
if (type && !RNA_struct_is_a(entry->ptr.type, type)) {
return nullptr;
}
return &entry->ptr;
} }
bContextStore *CTX_store_copy(bContextStore *store) bContextStore *CTX_store_copy(const bContextStore *store)
{ {
bContextStore *ctx = MEM_cnew<bContextStore>(__func__); return MEM_new<bContextStore>(__func__, *store);
*ctx = *store;
BLI_duplicatelist(&ctx->entries, &store->entries);
return ctx;
} }
void CTX_store_free(bContextStore *store) void CTX_store_free(bContextStore *store)
{ {
BLI_freelistN(&store->entries); MEM_delete(store);
MEM_freeN(store);
}
void CTX_store_free_list(ListBase *contexts)
{
bContextStore *ctx;
while ((ctx = static_cast<bContextStore *>(BLI_pophead(contexts)))) {
CTX_store_free(ctx);
}
} }
/* is python initialized? */ /* is python initialized? */
@@ -592,11 +567,8 @@ ListBase CTX_data_dir_get_ex(const bContext *C,
RNA_PROP_END; RNA_PROP_END;
} }
if (use_store && C->wm.store) { if (use_store && C->wm.store) {
bContextStoreEntry *entry; for (const bContextStoreEntry &entry : C->wm.store->entries) {
data_dir_add(&lb, entry.name.c_str(), use_all);
for (entry = static_cast<bContextStoreEntry *>(C->wm.store->entries.first); entry;
entry = entry->next) {
data_dir_add(&lb, entry->name, use_all);
} }
} }
if ((region = CTX_wm_region(C)) && region->type && region->type->context) { if ((region = CTX_wm_region(C)) && region->type && region->type->context) {

View File

@@ -3470,7 +3470,9 @@ void UI_block_free(const bContext *C, uiBlock *block)
MEM_freeN(block->func_argN); MEM_freeN(block->func_argN);
} }
CTX_store_free_list(&block->contexts); LISTBASE_FOREACH_MUTABLE (bContextStore *, store, &block->contexts) {
CTX_store_free(store);
}
BLI_freelistN(&block->saferct); BLI_freelistN(&block->saferct);
BLI_freelistN(&block->color_pickers.list); BLI_freelistN(&block->color_pickers.list);