Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h28
-rw-r--r--source/blender/blenkernel/intern/subdiv.c65
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter.h12
-rw-r--r--source/blender/blenkernel/intern/subdiv_stats.c4
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h4
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c30
7 files changed, 127 insertions, 17 deletions
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 81d605ffb63..d79ea1ca646 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -79,6 +79,7 @@ typedef enum eSubdivStatsValue {
SUBDIV_STATS_EVALUATOR_REFINE,
SUBDIV_STATS_SUBDIV_TO_CCG,
SUBDIV_STATS_SUBDIV_TO_CCG_ELEMENTS,
+ SUBDIV_STATS_TOPOLOGY_COMPARE,
NUM_SUBDIV_STATS_VALUES,
} eSubdivStatsValue;
@@ -102,6 +103,8 @@ typedef struct SubdivStats {
double subdiv_to_ccg_time;
/* Time spent on CCG elements evaluation/initialization. */
double subdiv_to_ccg_elements_time;
+ /* Time spent on CCG elements evaluation/initialization. */
+ double topology_compare_time;
};
double values_[NUM_SUBDIV_STATS_VALUES];
};
@@ -187,14 +190,37 @@ void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value);
void BKE_subdiv_stats_print(const SubdivStats *stats);
+/* ================================ SETTINGS ================================ */
+
+bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a,
+ const SubdivSettings *settings_b);
+
/* ============================== CONSTRUCTION ============================== */
+/* Construct new subdivision surface descriptor, from scratch, using given
+ * settings and topology. */
Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
struct OpenSubdiv_Converter *converter);
-
Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
const struct Mesh *mesh);
+/* Similar to above, but will not re-create descriptor if it was created for the
+ * same settings and topology.
+ * If settings or topology did change, the existing descriptor is freed and a
+ * new one is created from scratch.
+ *
+ * NOTE: It is allowed to pass NULL as an existing subdivision surface
+ * descriptor. This will create enw descriptor without any extra checks.
+ */
+Subdiv *BKE_subdiv_update_from_converter(
+ Subdiv *subdiv,
+ const SubdivSettings *settings,
+ struct OpenSubdiv_Converter *converter);
+Subdiv *BKE_subdiv_update_from_mesh(
+ Subdiv *subdiv,
+ const SubdivSettings *settings,
+ const struct Mesh *mesh);
+
void BKE_subdiv_free(Subdiv *subdiv);
/* ============================ DISPLACEMENT API ============================ */
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index 370448d117f..635cb64c772 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -66,8 +66,25 @@ BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
}
+/* ================================ SETTINGS ================================ */
+
+bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a,
+ const SubdivSettings *settings_b)
+{
+ return
+ (settings_a->is_simple == settings_b->is_simple &&
+ settings_a->is_adaptive == settings_b->is_adaptive &&
+ settings_a->level == settings_b->level &&
+ settings_a->vtx_boundary_interpolation ==
+ settings_b->vtx_boundary_interpolation &&
+ settings_a->fvar_linear_interpolation ==
+ settings_b->fvar_linear_interpolation);
+}
+
/* ============================== CONSTRUCTION ============================== */
+/* Creation from scratch. */
+
Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
struct OpenSubdiv_Converter *converter)
{
@@ -82,7 +99,6 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
osd_topology_refiner =
openSubdiv_createTopologyRefinerFromConverter(
converter, &topology_refiner_settings);
-
}
else {
/* TODO(sergey): Check whether original geometry had any vertices.
@@ -112,6 +128,53 @@ Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
return subdiv;
}
+/* Creation with cached-aware semantic. */
+
+Subdiv *BKE_subdiv_update_from_converter(Subdiv *subdiv,
+ const SubdivSettings *settings,
+ OpenSubdiv_Converter *converter)
+{
+ /* Check if the existing descriptor can be re-used. */
+ bool can_reuse_subdiv = true;
+ if (subdiv != NULL && subdiv->topology_refiner != NULL) {
+ if (!BKE_subdiv_settings_equal(&subdiv->settings, settings)) {
+ can_reuse_subdiv = false;
+ }
+ else {
+ BKE_subdiv_stats_begin(
+ &subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
+ can_reuse_subdiv = openSubdiv_topologyRefinerCompareWithConverter(
+ subdiv->topology_refiner, converter);
+ BKE_subdiv_stats_end(
+ &subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
+ }
+ }
+ else {
+ can_reuse_subdiv = false;
+ }
+ if (can_reuse_subdiv) {
+ return subdiv;
+ }
+ /* Create new subdiv. */
+ if (subdiv != NULL) {
+ BKE_subdiv_free(subdiv);
+ }
+ return BKE_subdiv_new_from_converter(settings, converter);
+}
+
+Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
+ const SubdivSettings *settings,
+ const Mesh *mesh)
+{
+ OpenSubdiv_Converter converter;
+ BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
+ subdiv = BKE_subdiv_update_from_converter(subdiv, settings, &converter);
+ BKE_subdiv_converter_free(&converter);
+ return subdiv;
+}
+
+/* Memory release. */
+
void BKE_subdiv_free(Subdiv *subdiv)
{
if (subdiv->evaluator != NULL) {
diff --git a/source/blender/blenkernel/intern/subdiv_converter.h b/source/blender/blenkernel/intern/subdiv_converter.h
index 17172bc29f7..fa5b15fa8d0 100644
--- a/source/blender/blenkernel/intern/subdiv_converter.h
+++ b/source/blender/blenkernel/intern/subdiv_converter.h
@@ -33,8 +33,7 @@
#include "BKE_subdiv.h"
/* NOTE: Was initially used to get proper enumerator types, but this makes
- * it tricky to compile without OpenSubdiv.
- */
+ * it tricky to compile without OpenSubdiv. */
/* #include "opensubdiv_converter_capi.h" */
struct Mesh;
@@ -46,21 +45,18 @@ void BKE_subdiv_converter_init_for_mesh(struct OpenSubdiv_Converter *converter,
const struct Mesh *mesh);
/* NOTE: Frees converter data, but not converter itself. This means, that if
- * converter was allocated on heap, it is up to the user to free that memory.
- */
+ * converter was allocated on heap, it is up to the user to free that memory. */
void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter);
/* ============================ INTERNAL HELPERS ============================ */
/* TODO(sergey): Find a way to make it OpenSubdiv_VtxBoundaryInterpolation,
- * without breaking compilation without OpenSubdiv.
- */
+ * without breaking compilation without OpenSubdiv. */
int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
const SubdivSettings *settings);
/* TODO(sergey): Find a way to make it OpenSubdiv_FVarLinearInterpolation,
- * without breaking compilation without OpenSubdiv.
- */
+ * without breaking compilation without OpenSubdiv. */
int BKE_subdiv_converter_fvar_linear_from_settings(
const SubdivSettings *settings);
diff --git a/source/blender/blenkernel/intern/subdiv_stats.c b/source/blender/blenkernel/intern/subdiv_stats.c
index a0cd1d909b7..370aedad04f 100644
--- a/source/blender/blenkernel/intern/subdiv_stats.c
+++ b/source/blender/blenkernel/intern/subdiv_stats.c
@@ -42,6 +42,7 @@ void BKE_subdiv_stats_init(SubdivStats *stats)
stats->evaluator_refine_time = 0.0;
stats->subdiv_to_ccg_time = 0.0;
stats->subdiv_to_ccg_elements_time = 0.0;
+ stats->topology_compare_time = 0.0;
}
void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value)
@@ -87,6 +88,9 @@ void BKE_subdiv_stats_print(const SubdivStats *stats)
STATS_PRINT_TIME(stats,
subdiv_to_ccg_elements_time,
" Elements time");
+ STATS_PRINT_TIME(stats,
+ topology_compare_time,
+ "Topology comparison time");
#undef STATS_PRINT_TIME
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index bc827abc933..0094a6a2f57 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -5073,6 +5073,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
SubsurfModifierData *smd = (SubsurfModifierData *)md;
smd->emCache = smd->mCache = NULL;
+ smd->subdiv = NULL;
}
else if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 6b71e6512a6..30c093ab3a8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -34,6 +34,7 @@
struct Mesh;
struct Scene;
+struct Subdiv;
typedef enum ModifierType {
eModifierType_None = 0,
@@ -167,7 +168,10 @@ typedef struct SubsurfModifierData {
short quality;
short pad[2];
+ /* TODO(sergey): Get rid of those with the old CCG subdivision code. */
void *emCache, *mCache;
+ /* Cached subdivision surface descriptor, with topology and settings. */
+ struct Subdiv *subdiv;
} SubsurfModifierData;
typedef struct LatticeModifierData {
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index e66b3fdbafb..6394ab458e7 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -89,6 +89,9 @@ static void freeData(ModifierData *md)
ccgSubSurf_free(smd->emCache);
smd->emCache = NULL;
}
+ if (smd->subdiv != NULL) {
+ BKE_subdiv_free(smd->subdiv);
+ }
}
static bool isDisabled(const Scene *scene, ModifierData *md, bool useRenderParams)
@@ -122,6 +125,20 @@ static void subdiv_settings_init(SubdivSettings *settings,
BKE_subdiv_fvar_interpolation_from_uv_smooth(smd->uv_smooth);
}
+/* Main goal of this function is to give usable subdivision surface descriptor
+ * which matches settings and topology. */
+static Subdiv *subdiv_descriptor_ensure(SubsurfModifierData *smd,
+ const SubdivSettings *subdiv_settings,
+ const Mesh *mesh)
+{
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(
+ smd->subdiv, subdiv_settings, mesh);
+ if (false) {
+ smd->subdiv = subdiv;
+ }
+ return subdiv;
+}
+
/* Subdivide into fully qualified mesh. */
static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
@@ -189,24 +206,23 @@ static Mesh *applyModifier(ModifierData *md,
if (subdiv_settings.level == 0) {
return result;
}
- /* TODO(sergey): Try to re-use subdiv when possible. */
- Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, mesh);
+ Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
if (subdiv == NULL) {
- /* Happens on bad topology, ut also on empty input mesh. */
+ /* Happens on bad topology, but also on empty input mesh. */
return result;
}
/* TODO(sergey): Decide whether we ever want to use CCG for subsurf,
- * maybe when it is a last modifier in the stack?
- */
+ * maybe when it is a last modifier in the stack? */
if (true) {
result = subdiv_as_mesh(smd, ctx, mesh, subdiv);
}
else {
result = subdiv_as_ccg(smd, ctx, mesh, subdiv);
}
- /* TODO(sergey): Cache subdiv somehow. */
// BKE_subdiv_stats_print(&subdiv->stats);
- BKE_subdiv_free(subdiv);
+ if (subdiv != smd->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
return result;
}