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:
parent
d59f6ffdcb
commit
7d7e90ca68
Notes:
blender-bot
2023-08-31 18:03:27 +02:00
Referenced by commit15c433d7d5
, Fix: Missing UI context members after recent refactor Referenced by issue #103417, Regression: Submenus in toolbar are empty Referenced by issue #103405, Regression: Some modifiers not working Referenced by commit1763a46cbf
, Cleanup: UI: Store uiBlock context stores in vector instead of list
|
@ -16,6 +16,11 @@
|
|||
#include "DNA_object_enums.h"
|
||||
#include "RNA_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "BLI_string_ref.hh"
|
||||
# include "BLI_vector.hh"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -84,19 +89,22 @@ typedef int /*eContextResult*/ (*bContextDataCallback)(const bContext *C,
|
|||
const char *member,
|
||||
bContextDataResult *result);
|
||||
|
||||
typedef struct bContextStoreEntry {
|
||||
struct bContextStoreEntry *next, *prev;
|
||||
#ifdef __cplusplus
|
||||
|
||||
char name[128];
|
||||
struct bContextStoreEntry {
|
||||
std::string name;
|
||||
PointerRNA ptr;
|
||||
} bContextStoreEntry;
|
||||
};
|
||||
|
||||
typedef struct bContextStore {
|
||||
struct bContextStore *next, *prev;
|
||||
struct bContextStore {
|
||||
bContextStore *next = nullptr;
|
||||
bContextStore *prev = nullptr;
|
||||
|
||||
ListBase entries;
|
||||
bool used;
|
||||
} bContextStore;
|
||||
blender::Vector<bContextStoreEntry> entries;
|
||||
bool used = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* for the context's rna mode enum
|
||||
* keep aligned with data_mode_strings in context.cc */
|
||||
|
@ -132,18 +140,23 @@ void CTX_free(bContext *C);
|
|||
|
||||
bContext *CTX_copy(const bContext *C);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/* 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_get(bContext *C);
|
||||
void CTX_store_set(bContext *C, bContextStore *store);
|
||||
const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store,
|
||||
const char *name,
|
||||
const StructRNA *type CPP_ARG_DEFAULT(nullptr));
|
||||
bContextStore *CTX_store_copy(bContextStore *store);
|
||||
blender::StringRefNull name,
|
||||
const StructRNA *type = nullptr);
|
||||
bContextStore *CTX_store_copy(const 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 */
|
||||
bool CTX_py_init_get(bContext *C);
|
||||
|
|
|
@ -126,7 +126,9 @@ void CTX_free(bContext *C)
|
|||
|
||||
/* 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
|
||||
* 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) {
|
||||
bContextStore *lastctx = ctx;
|
||||
ctx = MEM_new<bContextStore>(__func__);
|
||||
*ctx = *lastctx;
|
||||
BLI_duplicatelist(&ctx->entries, &lastctx->entries);
|
||||
ctx = MEM_new<bContextStore>(__func__, *ctx);
|
||||
}
|
||||
else {
|
||||
ctx = MEM_cnew<bContextStore>(__func__);
|
||||
ctx = MEM_new<bContextStore>(__func__);
|
||||
}
|
||||
|
||||
BLI_addtail(contexts, ctx);
|
||||
}
|
||||
|
||||
bContextStoreEntry *entry = MEM_cnew<bContextStoreEntry>(__func__);
|
||||
BLI_strncpy(entry->name, name, sizeof(entry->name));
|
||||
entry->ptr = *ptr;
|
||||
|
||||
BLI_addtail(&ctx->entries, entry);
|
||||
ctx->entries.append(bContextStoreEntry{name, *ptr});
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
@ -163,22 +158,17 @@ bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context)
|
|||
|
||||
if (!ctx || ctx->used) {
|
||||
if (ctx) {
|
||||
bContextStore *lastctx = ctx;
|
||||
ctx = MEM_new<bContextStore>(__func__);
|
||||
*ctx = *lastctx;
|
||||
BLI_duplicatelist(&ctx->entries, &lastctx->entries);
|
||||
ctx = MEM_new<bContextStore>(__func__, *ctx);
|
||||
}
|
||||
else {
|
||||
ctx = MEM_cnew<bContextStore>(__func__);
|
||||
ctx = MEM_new<bContextStore>(__func__);
|
||||
}
|
||||
|
||||
BLI_addtail(contexts, ctx);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bContextStoreEntry *, tentry, &context->entries) {
|
||||
bContextStoreEntry *entry = MEM_cnew<bContextStoreEntry>(__func__);
|
||||
*entry = *tentry;
|
||||
BLI_addtail(&ctx->entries, entry);
|
||||
for (const bContextStoreEntry &src_entry : context->entries) {
|
||||
ctx->entries.append(src_entry);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
|
@ -195,42 +185,27 @@ void CTX_store_set(bContext *C, bContextStore *store)
|
|||
}
|
||||
|
||||
const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store,
|
||||
const char *name,
|
||||
const blender::StringRefNull name,
|
||||
const StructRNA *type)
|
||||
{
|
||||
bContextStoreEntry *entry = static_cast<bContextStoreEntry *>(
|
||||
BLI_rfindstring(&store->entries, name, offsetof(bContextStoreEntry, name)));
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
for (auto entry = store->entries.rbegin(); entry != store->entries.rend(); ++entry) {
|
||||
if (entry->name == name) {
|
||||
if (type && RNA_struct_is_a(entry->ptr.type, type)) {
|
||||
return &entry->ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type && !RNA_struct_is_a(entry->ptr.type, type)) {
|
||||
return nullptr;
|
||||
}
|
||||
return &entry->ptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bContextStore *CTX_store_copy(bContextStore *store)
|
||||
bContextStore *CTX_store_copy(const bContextStore *store)
|
||||
{
|
||||
bContextStore *ctx = MEM_cnew<bContextStore>(__func__);
|
||||
*ctx = *store;
|
||||
BLI_duplicatelist(&ctx->entries, &store->entries);
|
||||
|
||||
return ctx;
|
||||
return MEM_new<bContextStore>(__func__, *store);
|
||||
}
|
||||
|
||||
void CTX_store_free(bContextStore *store)
|
||||
{
|
||||
BLI_freelistN(&store->entries);
|
||||
MEM_freeN(store);
|
||||
}
|
||||
|
||||
void CTX_store_free_list(ListBase *contexts)
|
||||
{
|
||||
bContextStore *ctx;
|
||||
while ((ctx = static_cast<bContextStore *>(BLI_pophead(contexts)))) {
|
||||
CTX_store_free(ctx);
|
||||
}
|
||||
MEM_delete(store);
|
||||
}
|
||||
|
||||
/* is python initialized? */
|
||||
|
@ -592,11 +567,8 @@ ListBase CTX_data_dir_get_ex(const bContext *C,
|
|||
RNA_PROP_END;
|
||||
}
|
||||
if (use_store && C->wm.store) {
|
||||
bContextStoreEntry *entry;
|
||||
|
||||
for (entry = static_cast<bContextStoreEntry *>(C->wm.store->entries.first); entry;
|
||||
entry = entry->next) {
|
||||
data_dir_add(&lb, entry->name, use_all);
|
||||
for (const bContextStoreEntry &entry : C->wm.store->entries) {
|
||||
data_dir_add(&lb, entry.name.c_str(), use_all);
|
||||
}
|
||||
}
|
||||
if ((region = CTX_wm_region(C)) && region->type && region->type->context) {
|
||||
|
|
|
@ -3470,7 +3470,9 @@ void UI_block_free(const bContext *C, uiBlock *block)
|
|||
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->color_pickers.list);
|
||||
|
|
Loading…
Reference in New Issue