fix for [#36260] 2,300 Objects Makes Blender Unresponsive
- performance of outliner was low because of unoptimal data structures. - now it uses BLI_mempool instead of custom mempool and GHash to make searches for duplicates faster. - also fix undesired behaviour of BLI_mempool_as_arrayN thanks to Campbell Barton and Lukas Tönne for helping me get a better fix put together.
This commit is contained in:
parent
91d148b891
commit
66a4077927
|
@ -678,9 +678,10 @@ void BKE_object_unlink(Object *ob)
|
||||||
SpaceOops *so = (SpaceOops *)sl;
|
SpaceOops *so = (SpaceOops *)sl;
|
||||||
|
|
||||||
if (so->treestore) {
|
if (so->treestore) {
|
||||||
TreeStoreElem *tselem = so->treestore->data;
|
TreeStoreElem *tselem;
|
||||||
int i;
|
BLI_mempool_iter iter;
|
||||||
for (i = 0; i < so->treestore->usedelem; i++, tselem++) {
|
BLI_mempool_iternew(so->treestore, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
if (tselem->id == (ID *)ob) tselem->id = NULL;
|
if (tselem->id == (ID *)ob) tselem->id = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,8 +354,18 @@ void BLI_mempool_as_array(BLI_mempool *pool, void **data)
|
||||||
*/
|
*/
|
||||||
void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
|
void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
|
||||||
{
|
{
|
||||||
void *data = MEM_mallocN((size_t)(BLI_mempool_count(pool) * pool->esize), allocstr);
|
char *data = MEM_mallocN((size_t)(pool->totused * pool->esize), allocstr);
|
||||||
BLI_mempool_as_array(pool, data);
|
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
|
||||||
|
if (data) {
|
||||||
|
BLI_mempool_iter iter;
|
||||||
|
char *elem, *p = data;
|
||||||
|
BLI_mempool_iternew(pool, &iter);
|
||||||
|
for (elem = BLI_mempool_iterstep(&iter); elem; elem = BLI_mempool_iterstep(&iter)) {
|
||||||
|
memcpy(p, elem, (size_t)pool->esize);
|
||||||
|
p += pool->esize;
|
||||||
|
}
|
||||||
|
BLI_assert((p - data) == pool->totused * pool->esize);
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
#include "BLI_edgehash.h"
|
#include "BLI_edgehash.h"
|
||||||
#include "BLI_threads.h"
|
#include "BLI_threads.h"
|
||||||
|
#include "BLI_mempool.h"
|
||||||
|
|
||||||
#include "BLF_translation.h"
|
#include "BLF_translation.h"
|
||||||
|
|
||||||
|
@ -5684,16 +5685,24 @@ static void lib_link_screen(FileData *fd, Main *main)
|
||||||
}
|
}
|
||||||
else if (sl->spacetype == SPACE_OUTLINER) {
|
else if (sl->spacetype == SPACE_OUTLINER) {
|
||||||
SpaceOops *so= (SpaceOops *)sl;
|
SpaceOops *so= (SpaceOops *)sl;
|
||||||
TreeStoreElem *tselem;
|
|
||||||
int a;
|
|
||||||
|
|
||||||
so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
|
so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
|
||||||
|
|
||||||
if (so->treestore) {
|
if (so->treestore) {
|
||||||
tselem = so->treestore->data;
|
TreeStoreElem *tselem;
|
||||||
for (a=0; a < so->treestore->usedelem; a++, tselem++) {
|
BLI_mempool_iter iter;
|
||||||
|
|
||||||
|
BLI_mempool_iternew(so->treestore, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
tselem->id = newlibadr(fd, NULL, tselem->id);
|
tselem->id = newlibadr(fd, NULL, tselem->id);
|
||||||
}
|
}
|
||||||
|
if (so->treehash) {
|
||||||
|
/* update hash table, because it depends on ids too */
|
||||||
|
BLI_ghash_clear(so->treehash, NULL, NULL);
|
||||||
|
BLI_mempool_iternew(so->treestore, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
|
BLI_ghash_insert(so->treehash, tselem, tselem);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sl->spacetype == SPACE_NODE) {
|
else if (sl->spacetype == SPACE_NODE) {
|
||||||
|
@ -6016,16 +6025,25 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
|
||||||
}
|
}
|
||||||
else if (sl->spacetype == SPACE_OUTLINER) {
|
else if (sl->spacetype == SPACE_OUTLINER) {
|
||||||
SpaceOops *so= (SpaceOops *)sl;
|
SpaceOops *so= (SpaceOops *)sl;
|
||||||
int a;
|
|
||||||
|
|
||||||
so->search_tse.id = restore_pointer_by_name(newmain, so->search_tse.id, 0);
|
so->search_tse.id = restore_pointer_by_name(newmain, so->search_tse.id, 0);
|
||||||
|
|
||||||
if (so->treestore) {
|
if (so->treestore) {
|
||||||
TreeStore *ts = so->treestore;
|
TreeStoreElem *tselem;
|
||||||
TreeStoreElem *tselem = ts->data;
|
BLI_mempool_iter iter;
|
||||||
for (a = 0; a < ts->usedelem; a++, tselem++) {
|
|
||||||
|
BLI_mempool_iternew(so->treestore, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
tselem->id = restore_pointer_by_name(newmain, tselem->id, 0);
|
tselem->id = restore_pointer_by_name(newmain, tselem->id, 0);
|
||||||
}
|
}
|
||||||
|
if (so->treehash) {
|
||||||
|
/* update hash table, because it depends on ids too */
|
||||||
|
BLI_ghash_clear(so->treehash, NULL, NULL);
|
||||||
|
BLI_mempool_iternew(so->treestore, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
|
BLI_ghash_insert(so->treehash, tselem, tselem);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sl->spacetype == SPACE_NODE) {
|
else if (sl->spacetype == SPACE_NODE) {
|
||||||
|
@ -6283,13 +6301,27 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
|
||||||
else if (sl->spacetype == SPACE_OUTLINER) {
|
else if (sl->spacetype == SPACE_OUTLINER) {
|
||||||
SpaceOops *soops = (SpaceOops *) sl;
|
SpaceOops *soops = (SpaceOops *) sl;
|
||||||
|
|
||||||
soops->treestore = newdataadr(fd, soops->treestore);
|
TreeStore *ts = newdataadr(fd, soops->treestore);
|
||||||
if (soops->treestore) {
|
soops->treestore = NULL;
|
||||||
soops->treestore->data = newdataadr(fd, soops->treestore->data);
|
if (ts) {
|
||||||
|
TreeStoreElem *elems = newdataadr(fd, ts->data);
|
||||||
|
|
||||||
|
soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), ts->usedelem,
|
||||||
|
512, BLI_MEMPOOL_ALLOW_ITER);
|
||||||
|
if (ts->usedelem && elems) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ts->usedelem; i++) {
|
||||||
|
TreeStoreElem *new_elem = BLI_mempool_alloc(soops->treestore);
|
||||||
|
*new_elem = elems[i];
|
||||||
|
}
|
||||||
|
MEM_freeN(elems);
|
||||||
|
}
|
||||||
/* we only saved what was used */
|
/* we only saved what was used */
|
||||||
soops->treestore->totelem = soops->treestore->usedelem;
|
|
||||||
soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw
|
soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw
|
||||||
|
|
||||||
|
MEM_freeN(ts);
|
||||||
}
|
}
|
||||||
|
soops->treehash = NULL;
|
||||||
soops->tree.first = soops->tree.last= NULL;
|
soops->tree.first = soops->tree.last= NULL;
|
||||||
}
|
}
|
||||||
else if (sl->spacetype == SPACE_IMAGE) {
|
else if (sl->spacetype == SPACE_IMAGE) {
|
||||||
|
|
|
@ -144,12 +144,13 @@
|
||||||
#include "BLI_bitmap.h"
|
#include "BLI_bitmap.h"
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
#include "BLI_linklist.h"
|
#include "BLI_linklist.h"
|
||||||
#include "BKE_bpath.h"
|
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
#include "BLI_mempool.h"
|
||||||
|
|
||||||
#include "BKE_action.h"
|
#include "BKE_action.h"
|
||||||
#include "BKE_blender.h"
|
#include "BKE_blender.h"
|
||||||
|
#include "BKE_bpath.h"
|
||||||
#include "BKE_curve.h"
|
#include "BKE_curve.h"
|
||||||
#include "BKE_constraint.h"
|
#include "BKE_constraint.h"
|
||||||
#include "BKE_global.h" // for G
|
#include "BKE_global.h" // for G
|
||||||
|
@ -2393,6 +2394,31 @@ static void write_region(WriteData *wd, ARegion *ar, int spacetype)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void write_soops(WriteData *wd, SpaceOops *so)
|
||||||
|
{
|
||||||
|
BLI_mempool *ts = so->treestore;
|
||||||
|
|
||||||
|
if (ts) {
|
||||||
|
int elems = BLI_mempool_count(ts);
|
||||||
|
/* linearize mempool to array */
|
||||||
|
TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL;
|
||||||
|
TreeStore ts_flat = {elems, elems, data};
|
||||||
|
|
||||||
|
/* temporarily replace mempool-treestore by flat-treestore */
|
||||||
|
so->treestore = (BLI_mempool *)&ts_flat;
|
||||||
|
writestruct(wd, DATA, "SpaceOops", 1, so);
|
||||||
|
/* restore old treestore */
|
||||||
|
so->treestore = ts;
|
||||||
|
writestruct(wd, DATA, "TreeStore", 1, &ts_flat);
|
||||||
|
if (data) {
|
||||||
|
writestruct(wd, DATA, "TreeStoreElem", elems, data);
|
||||||
|
MEM_freeN(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writestruct(wd, DATA, "SpaceOops", 1, so);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void write_screens(WriteData *wd, ListBase *scrbase)
|
static void write_screens(WriteData *wd, ListBase *scrbase)
|
||||||
{
|
{
|
||||||
bScreen *sc;
|
bScreen *sc;
|
||||||
|
@ -2475,15 +2501,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
|
||||||
}
|
}
|
||||||
else if (sl->spacetype==SPACE_OUTLINER) {
|
else if (sl->spacetype==SPACE_OUTLINER) {
|
||||||
SpaceOops *so= (SpaceOops *)sl;
|
SpaceOops *so= (SpaceOops *)sl;
|
||||||
|
write_soops(wd, so);
|
||||||
writestruct(wd, DATA, "SpaceOops", 1, so);
|
|
||||||
|
|
||||||
/* outliner */
|
|
||||||
if (so->treestore) {
|
|
||||||
writestruct(wd, DATA, "TreeStore", 1, so->treestore);
|
|
||||||
if (so->treestore->data)
|
|
||||||
writestruct(wd, DATA, "TreeStoreElem", so->treestore->usedelem, so->treestore->data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (sl->spacetype==SPACE_IMAGE) {
|
else if (sl->spacetype==SPACE_IMAGE) {
|
||||||
SpaceImage *sima= (SpaceImage *)sl;
|
SpaceImage *sima= (SpaceImage *)sl;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
#include "BLI_ghash.h"
|
#include "BLI_ghash.h"
|
||||||
|
#include "BLI_mempool.h"
|
||||||
|
|
||||||
#include "BLF_translation.h"
|
#include "BLF_translation.h"
|
||||||
|
|
||||||
|
@ -407,7 +408,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
|
||||||
SpaceOops *soops = CTX_wm_space_outliner(C);
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
||||||
Scene *scene = CTX_data_scene(C);
|
Scene *scene = CTX_data_scene(C);
|
||||||
Object *obedit = CTX_data_edit_object(C);
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
TreeStore *ts = soops->treestore;
|
BLI_mempool *ts = soops->treestore;
|
||||||
TreeStoreElem *tselem = tsep;
|
TreeStoreElem *tselem = tsep;
|
||||||
|
|
||||||
if (ts && tselem) {
|
if (ts && tselem) {
|
||||||
|
|
|
@ -984,7 +984,7 @@ static int ed_operator_outliner_datablocks_active(bContext *C)
|
||||||
* NOTE: the caller must zero-out all values of the pointers that it passes here first, as
|
* NOTE: the caller must zero-out all values of the pointers that it passes here first, as
|
||||||
* this function does not do that yet
|
* this function does not do that yet
|
||||||
*/
|
*/
|
||||||
static void tree_element_to_path(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem,
|
static void tree_element_to_path(TreeElement *te, TreeStoreElem *tselem,
|
||||||
ID **id, char **path, int *array_index, short *flag, short *UNUSED(groupmode))
|
ID **id, char **path, int *array_index, short *flag, short *UNUSED(groupmode))
|
||||||
{
|
{
|
||||||
ListBase hierarchy = {NULL, NULL};
|
ListBase hierarchy = {NULL, NULL};
|
||||||
|
@ -1152,7 +1152,7 @@ static void do_outliner_drivers_editop(SpaceOops *soops, ListBase *tree, ReportL
|
||||||
RNA_property_animateable(&te->rnaptr, te->directdata))
|
RNA_property_animateable(&te->rnaptr, te->directdata))
|
||||||
{
|
{
|
||||||
/* get id + path + index info from the selected element */
|
/* get id + path + index info from the selected element */
|
||||||
tree_element_to_path(soops, te, tselem,
|
tree_element_to_path(te, tselem,
|
||||||
&id, &path, &array_index, &flag, &groupmode);
|
&id, &path, &array_index, &flag, &groupmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1333,7 +1333,7 @@ static void do_outliner_keyingset_editop(SpaceOops *soops, KeyingSet *ks, ListBa
|
||||||
RNA_property_animateable(&te->rnaptr, te->directdata))
|
RNA_property_animateable(&te->rnaptr, te->directdata))
|
||||||
{
|
{
|
||||||
/* get id + path + index info from the selected element */
|
/* get id + path + index info from the selected element */
|
||||||
tree_element_to_path(soops, te, tselem,
|
tree_element_to_path(te, tselem,
|
||||||
&id, &path, &array_index, &flag, &groupmode);
|
&id, &path, &array_index, &flag, &groupmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,15 +48,15 @@ struct Object;
|
||||||
typedef struct TreeElement {
|
typedef struct TreeElement {
|
||||||
struct TreeElement *next, *prev, *parent;
|
struct TreeElement *next, *prev, *parent;
|
||||||
ListBase subtree;
|
ListBase subtree;
|
||||||
int xs, ys; // do selection
|
int xs, ys; // do selection
|
||||||
int store_index; // offset in tree store
|
TreeStoreElem *store_elem; // element in tree store
|
||||||
short flag; // flag for non-saved stuff
|
short flag; // flag for non-saved stuff
|
||||||
short index; // index for data arrays
|
short index; // index for data arrays
|
||||||
short idcode; // from TreeStore id
|
short idcode; // from TreeStore id
|
||||||
short xend; // width of item display, for select
|
short xend; // width of item display, for select
|
||||||
const char *name;
|
const char *name;
|
||||||
void *directdata; // Armature Bones, Base, Sequence, Strip...
|
void *directdata; // Armature Bones, Base, Sequence, Strip...
|
||||||
PointerRNA rnaptr; // RNA Pointer
|
PointerRNA rnaptr; // RNA Pointer
|
||||||
} TreeElement;
|
} TreeElement;
|
||||||
|
|
||||||
/* TreeElement->flag */
|
/* TreeElement->flag */
|
||||||
|
@ -111,7 +111,7 @@ typedef struct TreeElement {
|
||||||
/* get TreeStoreElem associated with a TreeElement
|
/* get TreeStoreElem associated with a TreeElement
|
||||||
* < a: (TreeElement) tree element to find stored element for
|
* < a: (TreeElement) tree element to find stored element for
|
||||||
*/
|
*/
|
||||||
#define TREESTORE(a) (soops->treestore->data + (a)->store_index)
|
#define TREESTORE(a) ((a)->store_elem)
|
||||||
|
|
||||||
/* size constants */
|
/* size constants */
|
||||||
#define OL_Y_OFFSET 2
|
#define OL_Y_OFFSET 2
|
||||||
|
@ -150,6 +150,7 @@ typedef struct TreeElement {
|
||||||
|
|
||||||
/* outliner_tree.c ----------------------------------------------- */
|
/* outliner_tree.c ----------------------------------------------- */
|
||||||
|
|
||||||
|
void outliner_rebuild_treehash(struct SpaceOops *soops);
|
||||||
void outliner_free_tree(ListBase *lb);
|
void outliner_free_tree(ListBase *lb);
|
||||||
void outliner_cleanup_tree(struct SpaceOops *soops);
|
void outliner_cleanup_tree(struct SpaceOops *soops);
|
||||||
|
|
||||||
|
|
|
@ -282,7 +282,7 @@ static int tree_element_active_material(bContext *C, Scene *scene, SpaceOops *so
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tree_element_active_texture(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
|
static int tree_element_active_texture(bContext *C, Scene *scene, SpaceOops *UNUSED(soops), TreeElement *te, int set)
|
||||||
{
|
{
|
||||||
TreeElement *tep;
|
TreeElement *tep;
|
||||||
TreeStoreElem /* *tselem,*/ *tselemp;
|
TreeStoreElem /* *tselem,*/ *tselemp;
|
||||||
|
@ -384,7 +384,7 @@ static int tree_element_active_camera(bContext *UNUSED(C), Scene *scene, SpaceOo
|
||||||
return scene->camera == ob;
|
return scene->camera == ob;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tree_element_active_world(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
|
static int tree_element_active_world(bContext *C, Scene *scene, SpaceOops *UNUSED(soops), TreeElement *te, int set)
|
||||||
{
|
{
|
||||||
TreeElement *tep;
|
TreeElement *tep;
|
||||||
TreeStoreElem *tselem = NULL;
|
TreeStoreElem *tselem = NULL;
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
#include "BLI_ghash.h"
|
||||||
|
|
||||||
#include "BKE_animsys.h"
|
#include "BKE_animsys.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
|
@ -298,13 +299,17 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
|
||||||
if (base == NULL)
|
if (base == NULL)
|
||||||
base = BKE_scene_base_find(scene, (Object *)tselem->id);
|
base = BKE_scene_base_find(scene, (Object *)tselem->id);
|
||||||
if (base) {
|
if (base) {
|
||||||
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
||||||
|
|
||||||
// check also library later
|
// check also library later
|
||||||
if (scene->obedit == base->object)
|
if (scene->obedit == base->object)
|
||||||
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
|
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
|
||||||
|
|
||||||
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
|
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
|
||||||
te->directdata = NULL;
|
te->directdata = NULL;
|
||||||
|
BLI_ghash_remove(soops->treehash, tselem, NULL, NULL);
|
||||||
tselem->id = NULL;
|
tselem->id = NULL;
|
||||||
|
BLI_ghash_insert(soops->treehash, tselem, tselem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,8 @@
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
|
#include "BLI_ghash.h"
|
||||||
|
#include "BLI_mempool.h"
|
||||||
|
|
||||||
#include "BLF_translation.h"
|
#include "BLF_translation.h"
|
||||||
|
|
||||||
|
@ -93,105 +95,127 @@
|
||||||
|
|
||||||
static void outliner_storage_cleanup(SpaceOops *soops)
|
static void outliner_storage_cleanup(SpaceOops *soops)
|
||||||
{
|
{
|
||||||
TreeStore *ts = soops->treestore;
|
BLI_mempool *ts = soops->treestore;
|
||||||
|
|
||||||
if (ts) {
|
if (ts) {
|
||||||
TreeStoreElem *tselem;
|
TreeStoreElem *tselem;
|
||||||
int a, unused = 0;
|
int unused = 0;
|
||||||
|
|
||||||
/* each element used once, for ID blocks with more users to have each a treestore */
|
/* each element used once, for ID blocks with more users to have each a treestore */
|
||||||
for (a = 0, tselem = ts->data; a < ts->usedelem; a++, tselem++) tselem->used = 0;
|
BLI_mempool_iter iter;
|
||||||
|
|
||||||
|
BLI_mempool_iternew(ts, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
|
tselem->used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* cleanup only after reading file or undo step, and always for
|
/* cleanup only after reading file or undo step, and always for
|
||||||
* RNA datablocks view in order to save memory */
|
* RNA datablocks view in order to save memory */
|
||||||
if (soops->storeflag & SO_TREESTORE_CLEANUP) {
|
if (soops->storeflag & SO_TREESTORE_CLEANUP) {
|
||||||
|
BLI_mempool_iternew(ts, &iter);
|
||||||
for (a = 0, tselem = ts->data; a < ts->usedelem; a++, tselem++) {
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
if (tselem->id == NULL) unused++;
|
if (tselem->id == NULL) unused++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unused) {
|
if (unused) {
|
||||||
if (ts->usedelem == unused) {
|
if (BLI_mempool_count(ts) == unused) {
|
||||||
MEM_freeN(ts->data);
|
BLI_mempool_destroy(ts);
|
||||||
ts->data = NULL;
|
soops->treestore = NULL;
|
||||||
ts->usedelem = ts->totelem = 0;
|
|
||||||
|
if (soops->treehash) {
|
||||||
|
BLI_ghash_free(soops->treehash, NULL, NULL);
|
||||||
|
soops->treehash = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TreeStoreElem *tsnewar, *tsnew;
|
TreeStoreElem *tsenew;
|
||||||
|
BLI_mempool *new_ts = BLI_mempool_create(sizeof(TreeStoreElem), BLI_mempool_count(ts) - unused,
|
||||||
tsnew = tsnewar = MEM_mallocN((ts->usedelem - unused) * sizeof(TreeStoreElem), "new tselem");
|
512, BLI_MEMPOOL_ALLOW_ITER);
|
||||||
for (a = 0, tselem = ts->data; a < ts->usedelem; a++, tselem++) {
|
BLI_mempool_iternew(ts, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
if (tselem->id) {
|
if (tselem->id) {
|
||||||
*tsnew = *tselem;
|
tsenew = BLI_mempool_alloc(new_ts);
|
||||||
tsnew++;
|
*tsenew = *tselem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BLI_mempool_destroy(ts);
|
||||||
|
soops->treestore = new_ts;
|
||||||
|
|
||||||
|
if (soops->treehash) {
|
||||||
|
/* update hash table to fix broken pointers */
|
||||||
|
BLI_ghash_clear(soops->treehash, NULL, NULL);
|
||||||
|
BLI_mempool_iternew(soops->treestore, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
|
BLI_ghash_insert(soops->treehash, tselem, tselem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MEM_freeN(ts->data);
|
|
||||||
ts->data = tsnewar;
|
|
||||||
ts->usedelem -= unused;
|
|
||||||
ts->totelem = ts->usedelem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX - THIS FUNCTION IS INCREDIBLY SLOW
|
static unsigned int tse_hash(const void *ptr)
|
||||||
* ... it can bring blenders tools and viewport to a grinding halt because of searching
|
{
|
||||||
* for duplicate items every times they are added.
|
const TreeStoreElem *tse = (const TreeStoreElem *)ptr;
|
||||||
*
|
unsigned int hash;
|
||||||
* TODO (possible speedups)
|
BLI_assert(tse->type || !tse->nr);
|
||||||
* - use a hash for duplicate (could even store a hash per type)
|
hash = BLI_ghashutil_inthash(SET_INT_IN_POINTER((tse->nr << 16) + tse->type));
|
||||||
* - use mempool for TreeElements
|
hash ^= BLI_ghashutil_inthash(tse->id);
|
||||||
* */
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tse_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const TreeStoreElem *tse_a = (const TreeStoreElem *)a;
|
||||||
|
const TreeStoreElem *tse_b = (const TreeStoreElem *)b;
|
||||||
|
return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id;
|
||||||
|
}
|
||||||
|
|
||||||
static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr)
|
static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr)
|
||||||
{
|
{
|
||||||
TreeStore *ts;
|
/* When treestore comes directly from readfile.c, treehash is empty;
|
||||||
TreeStoreElem *tselem;
|
* In this case we don't want to get TSE_CLOSED while adding elements one by one,
|
||||||
int a;
|
* that is why this function restores treehash */
|
||||||
|
bool restore_treehash = (soops->treestore && !soops->treehash);
|
||||||
|
TreeStoreElem *tselem, elem_template;
|
||||||
|
|
||||||
/* case 1; no TreeStore */
|
|
||||||
if (soops->treestore == NULL) {
|
if (soops->treestore == NULL) {
|
||||||
soops->treestore = MEM_callocN(sizeof(TreeStore), "treestore");
|
/* if treestore was not created in readfile.c, create it here */
|
||||||
|
soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
|
||||||
|
}
|
||||||
|
if (soops->treehash == NULL) {
|
||||||
|
soops->treehash = BLI_ghash_new(tse_hash, tse_cmp, "treehash");
|
||||||
}
|
}
|
||||||
ts = soops->treestore;
|
|
||||||
|
|
||||||
|
if (restore_treehash) {
|
||||||
|
BLI_mempool_iter iter;
|
||||||
|
BLI_mempool_iternew(soops->treestore, &iter);
|
||||||
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
||||||
|
BLI_ghash_insert(soops->treehash, tselem, tselem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* check if 'te' is in treestore */
|
/* check if 'te' is in treestore */
|
||||||
tselem = ts->data;
|
elem_template.type = type;
|
||||||
for (a = 0; a < ts->usedelem; a++, tselem++) {
|
elem_template.nr = type ? nr : 0; // we're picky! :)
|
||||||
if ((tselem->used == 0) && (tselem->type == type) && (tselem->id == id)) {
|
elem_template.id = id;
|
||||||
if ((type == 0) || (tselem->nr == nr)) {
|
tselem = BLI_ghash_lookup(soops->treehash, &elem_template);
|
||||||
te->store_index = a;
|
if (tselem && !tselem->used) {
|
||||||
tselem->used = 1;
|
te->store_elem = tselem;
|
||||||
return;
|
tselem->used = 1;
|
||||||
}
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add 1 element to treestore */
|
/* add 1 element to treestore */
|
||||||
if (ts->usedelem == ts->totelem) {
|
tselem = BLI_mempool_alloc(soops->treestore);
|
||||||
TreeStoreElem *tsnew;
|
|
||||||
|
|
||||||
tsnew = MEM_mallocN((ts->totelem + TS_CHUNK) * sizeof(TreeStoreElem), "treestore data");
|
|
||||||
if (ts->data) {
|
|
||||||
memcpy(tsnew, ts->data, ts->totelem * sizeof(TreeStoreElem));
|
|
||||||
MEM_freeN(ts->data);
|
|
||||||
}
|
|
||||||
ts->data = tsnew;
|
|
||||||
ts->totelem += TS_CHUNK;
|
|
||||||
}
|
|
||||||
|
|
||||||
tselem = ts->data + ts->usedelem;
|
|
||||||
|
|
||||||
tselem->type = type;
|
tselem->type = type;
|
||||||
if (type) tselem->nr = nr; // we're picky! :)
|
tselem->nr = type ? nr : 0;
|
||||||
else tselem->nr = 0;
|
|
||||||
tselem->id = id;
|
tselem->id = id;
|
||||||
tselem->used = 0;
|
tselem->used = 0;
|
||||||
tselem->flag = TSE_CLOSED;
|
tselem->flag = TSE_CLOSED;
|
||||||
te->store_index = ts->usedelem;
|
te->store_elem = tselem;
|
||||||
|
BLI_ghash_insert(soops->treehash, tselem, tselem);
|
||||||
ts->usedelem++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ********************************************************* */
|
/* ********************************************************* */
|
||||||
|
@ -216,15 +240,14 @@ void outliner_cleanup_tree(SpaceOops *soops)
|
||||||
outliner_storage_cleanup(soops);
|
outliner_storage_cleanup(soops);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find ith item from the treestore */
|
/* Find specific item from the treestore */
|
||||||
static TreeElement *outliner_find_tree_element(ListBase *lb, int store_index)
|
static TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
|
||||||
{
|
{
|
||||||
TreeElement *te = lb->first, *tes;
|
TreeElement *te, *tes;
|
||||||
while (te) {
|
for (te = lb->first; te; te = te->next) {
|
||||||
if (te->store_index == store_index) return te;
|
if (te->store_elem == store_elem) return te;
|
||||||
tes = outliner_find_tree_element(&te->subtree, store_index);
|
tes = outliner_find_tree_element(&te->subtree, store_elem);
|
||||||
if (tes) return tes;
|
if (tes) return tes;
|
||||||
te = te->next;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -232,23 +255,18 @@ static TreeElement *outliner_find_tree_element(ListBase *lb, int store_index)
|
||||||
/* tse is not in the treestore, we use its contents to find a match */
|
/* tse is not in the treestore, we use its contents to find a match */
|
||||||
TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
|
TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
|
||||||
{
|
{
|
||||||
TreeStore *ts = soops->treestore;
|
GHash *th = soops->treehash;
|
||||||
TreeStoreElem *tselem;
|
TreeStoreElem *tselem, tselem_template;
|
||||||
int a;
|
|
||||||
|
|
||||||
if (tse->id == NULL) return NULL;
|
if (tse->id == NULL) return NULL;
|
||||||
|
|
||||||
/* check if 'tse' is in treestore */
|
/* check if 'tse' is in treestore */
|
||||||
tselem = ts->data;
|
tselem_template.id = tse->id;
|
||||||
for (a = 0; a < ts->usedelem; a++, tselem++) {
|
tselem_template.type = tse->type;
|
||||||
if ((tse->type == 0 && tselem->type == 0) || (tselem->type == tse->type && tselem->nr == tse->nr)) {
|
tselem_template.nr = tse->type ? tse->nr : 0;
|
||||||
if (tselem->id == tse->id) {
|
tselem = BLI_ghash_lookup(th, &tselem_template);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tselem)
|
if (tselem)
|
||||||
return outliner_find_tree_element(&soops->tree, a);
|
return outliner_find_tree_element(&soops->tree, tselem);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -274,7 +292,7 @@ TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode)
|
ID *outliner_search_back(SpaceOops *UNUSED(soops), TreeElement *te, short idcode)
|
||||||
{
|
{
|
||||||
TreeStoreElem *tselem;
|
TreeStoreElem *tselem;
|
||||||
te = te->parent;
|
te = te->parent;
|
||||||
|
@ -1187,7 +1205,7 @@ static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *t
|
||||||
/* Hierarchy --------------------------------------------- */
|
/* Hierarchy --------------------------------------------- */
|
||||||
|
|
||||||
/* make sure elements are correctly nested */
|
/* make sure elements are correctly nested */
|
||||||
static void outliner_make_hierarchy(SpaceOops *soops, ListBase *lb)
|
static void outliner_make_hierarchy(ListBase *lb)
|
||||||
{
|
{
|
||||||
TreeElement *te, *ten, *tep;
|
TreeElement *te, *ten, *tep;
|
||||||
TreeStoreElem *tselem;
|
TreeStoreElem *tselem;
|
||||||
|
@ -1489,7 +1507,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
|
||||||
Object *ob;
|
Object *ob;
|
||||||
TreeElement *te = NULL, *ten;
|
TreeElement *te = NULL, *ten;
|
||||||
TreeStoreElem *tselem;
|
TreeStoreElem *tselem;
|
||||||
int show_opened = (soops->treestore == NULL); /* on first view, we open scenes */
|
int show_opened = !soops->treestore || !BLI_mempool_count(soops->treestore); /* on first view, we open scenes */
|
||||||
|
|
||||||
/* Are we looking for something - we want to tag parents to filter child matches
|
/* Are we looking for something - we want to tag parents to filter child matches
|
||||||
* - NOT in datablocks view - searching all datablocks takes way too long to be useful
|
* - NOT in datablocks view - searching all datablocks takes way too long to be useful
|
||||||
|
@ -1561,7 +1579,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
|
||||||
ten = outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
|
ten = outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
|
||||||
ten->directdata = base;
|
ten->directdata = base;
|
||||||
}
|
}
|
||||||
outliner_make_hierarchy(soops, &te->subtree);
|
outliner_make_hierarchy(&te->subtree);
|
||||||
/* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
|
/* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
|
||||||
for (base = sce->base.first; base; base = base->next) base->object->id.newid = NULL;
|
for (base = sce->base.first; base; base = base->next) base->object->id.newid = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1574,14 +1592,14 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
|
||||||
ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
||||||
ten->directdata = base;
|
ten->directdata = base;
|
||||||
}
|
}
|
||||||
outliner_make_hierarchy(soops, &soops->tree);
|
outliner_make_hierarchy(&soops->tree);
|
||||||
}
|
}
|
||||||
else if (soops->outlinevis == SO_VISIBLE) {
|
else if (soops->outlinevis == SO_VISIBLE) {
|
||||||
for (base = scene->base.first; base; base = base->next) {
|
for (base = scene->base.first; base; base = base->next) {
|
||||||
if (base->lay & scene->lay)
|
if (base->lay & scene->lay)
|
||||||
outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
outliner_make_hierarchy(soops, &soops->tree);
|
outliner_make_hierarchy(&soops->tree);
|
||||||
}
|
}
|
||||||
else if (soops->outlinevis == SO_GROUPS) {
|
else if (soops->outlinevis == SO_GROUPS) {
|
||||||
Group *group;
|
Group *group;
|
||||||
|
@ -1595,7 +1613,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
|
||||||
ten = outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
|
ten = outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
|
||||||
ten->directdata = NULL; /* eh, why? */
|
ten->directdata = NULL; /* eh, why? */
|
||||||
}
|
}
|
||||||
outliner_make_hierarchy(soops, &te->subtree);
|
outliner_make_hierarchy(&te->subtree);
|
||||||
/* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
|
/* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
|
||||||
for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL;
|
for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1610,7 +1628,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
|
||||||
ten->directdata = base;
|
ten->directdata = base;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outliner_make_hierarchy(soops, &soops->tree);
|
outliner_make_hierarchy(&soops->tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (soops->outlinevis == SO_SELECTED) {
|
else if (soops->outlinevis == SO_SELECTED) {
|
||||||
|
@ -1622,7 +1640,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outliner_make_hierarchy(soops, &soops->tree);
|
outliner_make_hierarchy(&soops->tree);
|
||||||
}
|
}
|
||||||
else if (soops->outlinevis == SO_SEQUENCE) {
|
else if (soops->outlinevis == SO_SEQUENCE) {
|
||||||
Sequence *seq;
|
Sequence *seq;
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
#include "BLI_mempool.h"
|
||||||
|
#include "BLI_ghash.h"
|
||||||
|
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_screen.h"
|
#include "BKE_screen.h"
|
||||||
|
@ -426,10 +428,11 @@ static void outliner_free(SpaceLink *sl)
|
||||||
|
|
||||||
outliner_free_tree(&soutliner->tree);
|
outliner_free_tree(&soutliner->tree);
|
||||||
if (soutliner->treestore) {
|
if (soutliner->treestore) {
|
||||||
if (soutliner->treestore->data) MEM_freeN(soutliner->treestore->data);
|
BLI_mempool_destroy(soutliner->treestore);
|
||||||
MEM_freeN(soutliner->treestore);
|
}
|
||||||
|
if (soutliner->treehash) {
|
||||||
|
BLI_ghash_free(soutliner->treehash, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* spacetype; init callback */
|
/* spacetype; init callback */
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#ifndef __DNA_OUTLINER_TYPES_H__
|
#ifndef __DNA_OUTLINER_TYPES_H__
|
||||||
#define __DNA_OUTLINER_TYPES_H__
|
#define __DNA_OUTLINER_TYPES_H__
|
||||||
|
|
||||||
|
#include "DNA_defs.h"
|
||||||
|
|
||||||
struct ID;
|
struct ID;
|
||||||
|
|
||||||
typedef struct TreeStoreElem {
|
typedef struct TreeStoreElem {
|
||||||
|
@ -39,9 +41,12 @@ typedef struct TreeStoreElem {
|
||||||
struct ID *id;
|
struct ID *id;
|
||||||
} TreeStoreElem;
|
} TreeStoreElem;
|
||||||
|
|
||||||
|
/* used only to store data in in blend files */
|
||||||
typedef struct TreeStore {
|
typedef struct TreeStore {
|
||||||
int totelem, usedelem;
|
int totelem DNA_DEPRECATED; /* was previously used for memory preallocation */
|
||||||
TreeStoreElem *data;
|
int usedelem; /* number of elements in data array */
|
||||||
|
TreeStoreElem *data; /* elements to be packed from mempool in writefile.c
|
||||||
|
* or extracted to mempool in readfile.c */
|
||||||
} TreeStore;
|
} TreeStore;
|
||||||
|
|
||||||
/* TreeStoreElem->flag */
|
/* TreeStoreElem->flag */
|
||||||
|
|
|
@ -72,6 +72,8 @@ struct wmTimer;
|
||||||
struct MovieClip;
|
struct MovieClip;
|
||||||
struct MovieClipScopes;
|
struct MovieClipScopes;
|
||||||
struct Mask;
|
struct Mask;
|
||||||
|
struct GHash;
|
||||||
|
struct BLI_mempool;
|
||||||
|
|
||||||
|
|
||||||
/* SpaceLink (Base) ==================================== */
|
/* SpaceLink (Base) ==================================== */
|
||||||
|
@ -244,13 +246,14 @@ typedef struct SpaceOops {
|
||||||
View2D v2d DNA_DEPRECATED; /* deprecated, copied to region */
|
View2D v2d DNA_DEPRECATED; /* deprecated, copied to region */
|
||||||
|
|
||||||
ListBase tree;
|
ListBase tree;
|
||||||
struct TreeStore *treestore;
|
struct BLI_mempool *treestore;
|
||||||
|
|
||||||
/* search stuff */
|
/* search stuff */
|
||||||
char search_string[32];
|
char search_string[32];
|
||||||
struct TreeStoreElem search_tse;
|
struct TreeStoreElem search_tse;
|
||||||
|
|
||||||
short flag, outlinevis, storeflag, search_flags;
|
short flag, outlinevis, storeflag, search_flags;
|
||||||
|
struct GHash *treehash;
|
||||||
} SpaceOops;
|
} SpaceOops;
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue