[Bf-blender-cvs] [c1ce838] opensubdiv-modifier: Made evaluator persistent in memory

Sergey Sharybin noreply at git.blender.org
Mon May 12 20:08:56 CEST 2014


Commit: c1ce838be5bb34f9e1aa3b11b5cccad394e3d411
Author: Sergey Sharybin
Date:   Sat May 10 17:45:21 2014 +0200
https://developer.blender.org/rBc1ce838be5bb34f9e1aa3b11b5cccad394e3d411

Made evaluator persistent in memory

Now OpenSubdiv evaluator descriptor will only be re-created
if mesh topology changes.

Apparently don't see huge speed raise with CPU evaluation,
but this change lands a bit of a basis for further changes.

Requires changes made in OpenSubdiv's C-API which are currently
only there:

  https://github.com/Nazg-Gul/OpenSubdiv/tree/dev

===================================================================

M	source/blender/blenkernel/intern/CCGSubSurf.c
M	source/blender/blenkernel/intern/subsurf_ccg.c

===================================================================

diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index bb75bc4..a1afba6 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -2369,24 +2369,82 @@ static bool opensubdiv_initEvaluator(CCGSubSurf *ss)
 	return openSubdiv_finishEvaluatorDescr(ss->osd_evaluator, ss->subdivLevels) != 0;
 }
 
+static bool check_topology_changed(CCGSubSurf *ss)
+{
+	int num_vertices,
+	    refinement_level,
+	    num_indices,
+	    num_nverts;
+	int *indices, *nverts;
+	int i, index, osd_vert_index, osd_face_index;
+
+	BLI_assert(ss->osd_evaluator != NULL);
+
+	/* Set an osd_index member in each one so we have consistent indexing.
+	 *
+	 * TODO(sergey): Currently here's a duplicated logic happens, make it
+	 * so osd_indices are only calculated once.
+	 */
+	for (i = 0, osd_vert_index = 0; i < ss->vMap->curSize; ++i) {
+		CCGVert *vert = (CCGVert *) ss->vMap->buckets[i];
+		for (; vert; vert = vert->next, ++osd_vert_index) {
+			vert->osd_index = osd_vert_index;
+		}
+	}
+
+	/* Get the topology from existing evaluator. */
+	openSubdiv_getEvaluatorTopology(ss->osd_evaluator,
+	                                &num_vertices,
+	                                &refinement_level,
+	                                &num_indices,
+	                                &indices,
+	                                &num_nverts,
+	                                &nverts);
+
+	/* Quick tests based on the number of subdiv level, verts and facces. */
+	if (refinement_level != ss->subdivLevels ||
+	    num_vertices != ss->vMap->numEntries ||
+	    num_nverts != ss->fMap->numEntries)
+	{
+		return true;
+	}
+
+	/* Rather slow check for faces topology change. */
+	for (i = 0, osd_face_index = 0, index = 0;
+	     i < ss->fMap->curSize;
+	     i++)
+	{
+		CCGFace *face = (CCGFace *) ss->fMap->buckets[i];
+		for (; face; face = face->next, ++osd_face_index) {
+			int S;
+
+			if (face->numVerts != nverts[osd_face_index]) {
+				return true;
+			}
+
+			for (S = 0; S < face->numVerts; ++S) {
+				if (FACE_getVerts(face)[S]->osd_index != indices[index++]) {
+					return true;
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
 static bool opensubdiv_ensureEvaluator(CCGSubSurf *ss)
 {
 	bool evaluator_needs_init = false;
 
 	if (ss->osd_evaluator != NULL) {
-		/* TODO(dirk, sergey): Need to check that the existing evaluator has matching:
-		 * - Number of vertices
-		 * - Face topology
-		 *  - Subdivision level
-		 *
-		 * If not we need to blow away and recreate the evaluator.
-		 *
-		 * For now we always re-create the evaluator to be sure edit mode works all
-		 * fine and no topology changes caused by the previous modifiers are screwing
-		 * us up.
-		 */
-		openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
-		ss->osd_evaluator = NULL;
+		if (check_topology_changed(ss)) {
+			/* If topology changes then we are to re-create evaluator
+			 * from the very scratch.
+			 */
+			openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
+			ss->osd_evaluator = NULL;
+		}
 	}
 	if (ss->osd_evaluator == NULL) {
 		int num_basis_verts = ss->vMap->numEntries;
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index a9eba54..57aca4f 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -3918,16 +3918,31 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
 		}
 		else {
 			CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS;
-			
+			CCGSubSurf *prevSS = NULL;
+
 			if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) {
+#ifdef WITH_OPENSUBDIV
+				/* With OpenSubdiv enabled we always tries to re-use previos
+				 * subsurf structure in order to save computation time since
+				 * re-creation is rather a complicated business.
+				 *
+				 * TODO(sergey): There was a good eason why final calculation
+				 * used to free entirely cached subsurf structure. reason of
+				 * this is to be investiated still to be sure we don't have
+				 * regressions here.
+				 */
+				prevSS = smd->mCache;
+#else
 				ccgSubSurf_free(smd->mCache);
 				smd->mCache = NULL;
+#endif
 			}
 
+
 			if (flags & SUBSURF_ALLOC_PAINT_MASK)
 				ccg_flags |= CCG_ALLOC_MASK;
 
-			ss = _getSubSurf(NULL, levels, 3, ccg_flags);
+			ss = _getSubSurf(prevSS, levels, 3, ccg_flags);
 			ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
 
 			result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);




More information about the Bf-blender-cvs mailing list