Modifier stack: Avoid roundtrip from mesh to DM back to mesh
Saves quite a bit of CPU ticks per mesh update, giving measurable speedup for file from T55228. Memory usage goes up a it, most likely due to evaluated mesh having more custom data layers than corresponding DM does.
This commit is contained in:
parent
da16cb1511
commit
29f9a19708
|
@ -2916,6 +2916,47 @@ static bool calc_modifiers_skip_orco(Depsgraph *depsgraph,
|
|||
}
|
||||
#endif
|
||||
|
||||
static void mesh_finalize_eval(Object *object)
|
||||
{
|
||||
if (!DEG_depsgraph_use_copy_on_write()) {
|
||||
return;
|
||||
}
|
||||
Mesh *mesh = (Mesh *)object->data;
|
||||
Mesh *mesh_eval = object->runtime.mesh_eval;
|
||||
/* Special Tweaks for cases when evaluated mesh came from
|
||||
* BKE_mesh_new_nomain_from_template().
|
||||
*/
|
||||
BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name));
|
||||
if (mesh_eval->mat != NULL) {
|
||||
MEM_freeN(mesh_eval->mat);
|
||||
}
|
||||
mesh_eval->mat = MEM_dupallocN(mesh->mat);
|
||||
mesh_eval->totcol = mesh->totcol;
|
||||
/* Make evaluated mesh to share same edit mesh pointer as original
|
||||
* and copied meshes.
|
||||
*/
|
||||
mesh_eval->edit_btmesh = mesh->edit_btmesh;
|
||||
/* Special flags to help debugging and also to allow copy-on-write core
|
||||
* to understand that on re-evaluation this mesh is to be preserved and
|
||||
* to be remapped back to copied original mesh when used as object data.
|
||||
*/
|
||||
mesh_eval->id.tag |= LIB_TAG_COPY_ON_WRITE_EVAL;
|
||||
mesh_eval->id.orig_id = &mesh->id;
|
||||
/* Copy autosmooth settings from original mesh.
|
||||
* This is not done by BKE_mesh_new_nomain_from_template(), so need to take
|
||||
* extra care here.
|
||||
*/
|
||||
mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH);
|
||||
mesh_eval->smoothresh = mesh->smoothresh;
|
||||
/* Replace evaluated object's data with fully evaluated mesh. */
|
||||
/* TODO(sergey): There was statement done by Sybren and Mai that this
|
||||
* caused modifiers to be applied twice. which is weirtd and shouldn't
|
||||
* really happen. But since there is no reference to the report, can not
|
||||
* do much about this.
|
||||
*/
|
||||
object->data = mesh_eval;
|
||||
}
|
||||
|
||||
static void mesh_build_data(
|
||||
struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask,
|
||||
const bool build_shapekey_layers, const bool need_mapping)
|
||||
|
@ -2931,12 +2972,21 @@ static void mesh_build_data(
|
|||
}
|
||||
#endif
|
||||
|
||||
mesh_calc_modifiers_dm(
|
||||
mesh_calc_modifiers(
|
||||
depsgraph, scene, ob, NULL, 1, need_mapping, dataMask, -1, true, build_shapekey_layers,
|
||||
true,
|
||||
&ob->derivedDeform, &ob->derivedFinal);
|
||||
&ob->runtime.mesh_deform_eval, &ob->runtime.mesh_eval);
|
||||
|
||||
mesh_finalize_eval(ob);
|
||||
|
||||
ob->derivedDeform = CDDM_from_mesh_ex(ob->runtime.mesh_deform_eval, CD_REFERENCE, CD_MASK_MESH);
|
||||
ob->derivedFinal = CDDM_from_mesh_ex(ob->runtime.mesh_eval, CD_REFERENCE, CD_MASK_MESH);
|
||||
|
||||
DM_set_object_boundbox(ob, ob->derivedFinal);
|
||||
/* TODO(sergey): Convert bounding box calculation to use mesh, then
|
||||
* we can skip this copy.
|
||||
*/
|
||||
BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
|
||||
|
||||
ob->derivedFinal->needsFree = 0;
|
||||
ob->derivedDeform->needsFree = 0;
|
||||
|
|
|
@ -330,62 +330,6 @@ void BKE_object_eval_uber_data(Depsgraph *depsgraph,
|
|||
BKE_mball_batch_cache_dirty(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (DEG_depsgraph_use_copy_on_write()) {
|
||||
if (ob->type == OB_MESH) {
|
||||
/* Quick hack to convert evaluated derivedMesh to Mesh. */
|
||||
DerivedMesh *dm = ob->derivedFinal;
|
||||
if (dm != NULL) {
|
||||
Mesh *mesh = (Mesh *)ob->data;
|
||||
Mesh *new_mesh = BKE_libblock_alloc_notest(ID_ME);
|
||||
BKE_mesh_init(new_mesh);
|
||||
/* Copy ID name so GS(new_mesh->id) works correct later on. */
|
||||
BLI_strncpy(new_mesh->id.name, mesh->id.name, sizeof(new_mesh->id.name));
|
||||
/* Copy materials so render engines can access them. */
|
||||
new_mesh->mat = MEM_dupallocN(mesh->mat);
|
||||
new_mesh->totcol = mesh->totcol;
|
||||
DM_to_mesh(dm, new_mesh, ob, CD_MASK_MESH, true);
|
||||
new_mesh->edit_btmesh = mesh->edit_btmesh;
|
||||
/* Store result mesh as derived_mesh of object. This way we have
|
||||
* explicit way to query final object evaluated data and know for sure
|
||||
* who owns the newly created mesh datablock.
|
||||
*/
|
||||
ob->runtime.mesh_eval = new_mesh;
|
||||
/* TODO(sergey): This is kind of compatibility thing, so all render
|
||||
* engines can use object->data for mesh data for display. This is
|
||||
* something what we might want to change in the future.
|
||||
* XXX: This can sometimes cause modifiers to be applied twice!
|
||||
*/
|
||||
ob->data = new_mesh;
|
||||
/* Special flags to help debugging. */
|
||||
new_mesh->id.tag |= LIB_TAG_COPY_ON_WRITE_EVAL;
|
||||
/* Save some memory by throwing DerivedMesh away. */
|
||||
/* NOTE: Watch out, some tools might need it!
|
||||
* So keep around for now..
|
||||
*/
|
||||
/* Store original ID as a pointer in evaluated ID.
|
||||
* This way we can restore original object data when we are freeing
|
||||
* evaluated mesh.
|
||||
*/
|
||||
new_mesh->id.orig_id = &mesh->id;
|
||||
/* Copy autosmooth settings from original mesh. */
|
||||
new_mesh->flag |= (mesh->flag & ME_AUTOSMOOTH);
|
||||
new_mesh->smoothresh = mesh->smoothresh;
|
||||
}
|
||||
#if 0
|
||||
if (ob->derivedFinal != NULL) {
|
||||
ob->derivedFinal->needsFree = 1;
|
||||
ob->derivedFinal->release(ob->derivedFinal);
|
||||
ob->derivedFinal = NULL;
|
||||
}
|
||||
if (ob->derivedDeform != NULL) {
|
||||
ob->derivedDeform->needsFree = 1;
|
||||
ob->derivedDeform->release(ob->derivedDeform);
|
||||
ob->derivedDeform = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_eval_cloth(Depsgraph *depsgraph,
|
||||
|
|
Loading…
Reference in New Issue