[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [59440] trunk/blender/source/blender: Fix state losses for recursive outliner trees (e.g.

Sv. Lockal lockalsash at gmail.com
Fri Aug 23 22:35:01 CEST 2013


Revision: 59440
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=59440
Author:   lockal
Date:     2013-08-23 20:35:00 +0000 (Fri, 23 Aug 2013)
Log Message:
-----------
Fix state losses for recursive outliner trees (e.g. datablocks editor)

In previous optimization in outliner I assumed that order in treehash was not important.
But testing outliner in datablocks mode revealed a problem: when user expands multiple recursive levels and then closes any element, it always closed the top level of recursion.
Now it should work fine with recursive trees.
Now treehash contains groups of elements indexed by (id,nr,type). Adding an element with the same (id,nr,type) results in appending it to existing group. No duplicates are possible in treehash.
This commit should also make lookups a little bit faster, because searching in small arrays by "used" is faster than searching in hashtable with duplicates by "id,nr,type,used".

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/CMakeLists.txt
    trunk/blender/source/blender/blenlib/BLI_ghash.h
    trunk/blender/source/blender/blenloader/intern/readfile.c
    trunk/blender/source/blender/editors/space_outliner/outliner_tools.c
    trunk/blender/source/blender/editors/space_outliner/outliner_tree.c
    trunk/blender/source/blender/editors/space_outliner/space_outliner.c
    trunk/blender/source/blender/makesdna/DNA_space_types.h

Added Paths:
-----------
    trunk/blender/source/blender/blenkernel/BKE_treehash.h
    trunk/blender/source/blender/blenkernel/intern/treehash.c

Added: trunk/blender/source/blender/blenkernel/BKE_treehash.h
===================================================================
--- trunk/blender/source/blender/blenkernel/BKE_treehash.h	                        (rev 0)
+++ trunk/blender/source/blender/blenkernel/BKE_treehash.h	2013-08-23 20:35:00 UTC (rev 59440)
@@ -0,0 +1,52 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation 2013
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_TREEHASH_H__
+#define __BKE_TREEHASH_H__
+
+/** \file BKE_treehash.h
+ *  \ingroup bke
+ */
+
+struct ID;
+struct GHash;
+struct BLI_mempool;
+struct TreeStoreElem;
+
+/* create and fill hashtable with treestore elements */
+void *BKE_treehash_create_from_treestore(struct BLI_mempool *treestore);
+
+/* full rebuild for already allocated hashtable */
+void *BKE_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore);
+
+/* full rebuild for already allocated hashtable */
+void BKE_treehash_add_element(void *treehash, struct TreeStoreElem *elem);
+
+/* find first unused element with specific type, nr and id */
+struct TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id);
+
+/* find user or unused element with specific type, nr and id */
+struct TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id);
+
+/* free treehash structure */
+void BKE_treehash_free(void *treehash);
+
+#endif

Modified: trunk/blender/source/blender/blenkernel/CMakeLists.txt
===================================================================
--- trunk/blender/source/blender/blenkernel/CMakeLists.txt	2013-08-23 20:11:11 UTC (rev 59439)
+++ trunk/blender/source/blender/blenkernel/CMakeLists.txt	2013-08-23 20:35:00 UTC (rev 59440)
@@ -153,6 +153,7 @@
 	intern/text.c
 	intern/texture.c
 	intern/tracking.c
+	intern/treehash.c
 	intern/unit.c
 	intern/world.c
 	intern/writeavi.c
@@ -244,6 +245,7 @@
 	BKE_text.h
 	BKE_texture.h
 	BKE_tracking.h
+	BKE_treehash.h
 	BKE_unit.h
 	BKE_utildefines.h
 	BKE_world.h

Added: trunk/blender/source/blender/blenkernel/intern/treehash.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/treehash.c	                        (rev 0)
+++ trunk/blender/source/blender/blenkernel/intern/treehash.c	2013-08-23 20:35:00 UTC (rev 59440)
@@ -0,0 +1,133 @@
+#include "BKE_treehash.h"
+
+#include "BLI_ghash.h"
+#include "BLI_mempool.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_outliner_types.h"
+
+#include "MEM_guardedalloc.h"
+
+typedef struct TseGroup
+{
+	TreeStoreElem **elems;
+	int size;
+	int allocated;
+} TseGroup;
+
+/* Allocate structure for TreeStoreElements;
+ * Most of elements in treestore have no duplicates,
+ * so there is no need to preallocate memory for more than one pointer */
+static TseGroup *tse_group_create(void)
+{
+	TseGroup *tse_group = MEM_mallocN(sizeof(TseGroup), "TseGroup");
+	tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems");
+	tse_group->size = 0;
+	tse_group->allocated = 1;
+	return tse_group;
+}
+
+static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
+{
+	if (tse_group->size == tse_group->allocated) {
+		tse_group->allocated *= 2;
+		tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
+	}
+	tse_group->elems[tse_group->size] = elem;
+	tse_group->size++;
+}
+
+static void tse_group_free(TseGroup *tse_group)
+{
+	MEM_freeN(tse_group->elems);
+	MEM_freeN(tse_group);
+}
+
+static unsigned int tse_hash(const void *ptr)
+{
+	const TreeStoreElem *tse = ptr;
+	unsigned int hash;
+	BLI_assert(tse->type || !tse->nr);
+	hash = BLI_ghashutil_inthash(SET_INT_IN_POINTER((tse->nr << 16) + tse->type));
+	hash ^= BLI_ghashutil_inthash(tse->id);
+	return hash;
+}
+
+static int tse_cmp(const void *a, const void *b)
+{
+	const TreeStoreElem *tse_a = a;
+	const TreeStoreElem *tse_b = b;
+	return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id;
+}
+
+static void fill_treehash(void *treehash, BLI_mempool *treestore)
+{
+	TreeStoreElem *tselem;
+	BLI_mempool_iter iter;
+	BLI_mempool_iternew(treestore, &iter);
+	while ((tselem = BLI_mempool_iterstep(&iter))) {
+		BKE_treehash_add_element(treehash, tselem);
+	}
+}
+
+void *BKE_treehash_create_from_treestore(BLI_mempool *treestore)
+{
+	GHash *treehash = BLI_ghash_new(tse_hash, tse_cmp, "treehash");
+	fill_treehash(treehash, treestore);
+	return treehash;
+}
+
+static void free_treehash_group(void *key) {
+	tse_group_free(key);
+}
+
+void *BKE_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
+{
+	BLI_ghash_clear(treehash, NULL, free_treehash_group);
+	fill_treehash(treehash, treestore);
+	return treehash;
+}
+
+void BKE_treehash_add_element(void *treehash, TreeStoreElem *elem)
+{
+	TseGroup *group = BLI_ghash_lookup(treehash, elem);
+	if (!group) {
+		group = tse_group_create();
+		BLI_ghash_insert(treehash, elem, group);
+	}
+	tse_group_add(group, elem);
+}
+
+static TseGroup *BKE_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
+{
+	TreeStoreElem tse_template;
+	tse_template.type = type;
+	tse_template.nr = type ? nr : 0;  // we're picky! :)
+	tse_template.id = id;
+	return BLI_ghash_lookup(th, &tse_template);
+}
+
+TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
+{
+	TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id);
+	if (group) {
+		int i;
+		for (i = 0; i < group->size; i++) {
+			if (!group->elems[i]->used) {
+				return group->elems[i];
+			}
+		}
+	}
+	return NULL;
+}
+
+TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id)
+{
+	TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id);
+	return group ? group->elems[0] : NULL;
+}
+
+void BKE_treehash_free(void *treehash)
+{
+	BLI_ghash_free(treehash, NULL, free_treehash_group);
+}

Modified: trunk/blender/source/blender/blenlib/BLI_ghash.h
===================================================================
--- trunk/blender/source/blender/blenlib/BLI_ghash.h	2013-08-23 20:11:11 UTC (rev 59439)
+++ trunk/blender/source/blender/blenlib/BLI_ghash.h	2013-08-23 20:35:00 UTC (rev 59440)
@@ -33,6 +33,8 @@
  *  \brief A general (pointer -> pointer) hash table ADT
  */
 
+#include "BLI_sys_types.h" /* for bool */
+
 #ifdef __cplusplus
 extern "C" {
 #endif

Modified: trunk/blender/source/blender/blenloader/intern/readfile.c
===================================================================
--- trunk/blender/source/blender/blenloader/intern/readfile.c	2013-08-23 20:11:11 UTC (rev 59439)
+++ trunk/blender/source/blender/blenloader/intern/readfile.c	2013-08-23 20:35:00 UTC (rev 59440)
@@ -151,6 +151,7 @@
 #include "BKE_text.h" // for txt_extended_ascii_as_utf8
 #include "BKE_texture.h"
 #include "BKE_tracking.h"
+#include "BKE_treehash.h"
 #include "BKE_sound.h"
 
 #include "IMB_imbuf.h"  // for proxy / timecode versioning stuff
@@ -5701,12 +5702,8 @@
 								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);
-								}
+								/* rebuild hash table, because it depends on ids too */
+								BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore);
 							}
 						}
 					}
@@ -6042,12 +6039,8 @@
 							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);
-							}
+							/* rebuild hash table, because it depends on ids too */
+							BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore);
 						}
 					}
 				}
@@ -6322,7 +6315,7 @@
 			else if (sl->spacetype == SPACE_OUTLINER) {
 				SpaceOops *soops = (SpaceOops *) sl;
 				
-				/* use newdataadr_no_us and do not free old memory avoidign double
+				/* use newdataadr_no_us and do not free old memory avoiding double
 				 * frees and use of freed memory. this could happen because of a
 				 * bug fixed in revision 58959 where the treestore memory address
 				 * was not unique */

Modified: trunk/blender/source/blender/editors/space_outliner/outliner_tools.c
===================================================================
--- trunk/blender/source/blender/editors/space_outliner/outliner_tools.c	2013-08-23 20:11:11 UTC (rev 59439)
+++ trunk/blender/source/blender/editors/space_outliner/outliner_tools.c	2013-08-23 20:35:00 UTC (rev 59440)
@@ -57,6 +57,7 @@
 #include "BKE_report.h"
 #include "BKE_scene.h"
 #include "BKE_sequencer.h"
+#include "BKE_treehash.h"
 
 #include "ED_armature.h"
 #include "ED_object.h"
@@ -299,17 +300,13 @@
 	if (base == NULL)
 		base = BKE_scene_base_find(scene, (Object *)tselem->id);
 	if (base) {
-		SpaceOops *soops = CTX_wm_space_outliner(C);
-
 		// check also library later
 		if (scene->obedit == base->object)
 			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);
 		te->directdata = NULL;
-		BLI_ghash_remove(soops->treehash, tselem, NULL, NULL);
 		tselem->id = NULL;
-		BLI_ghash_insert(soops->treehash, tselem, tselem);
 	}
 }
 


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list