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:
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user