Modifiers: Use implicit sharing for some bind data

Addresses #145680.

In one (relatively extreme) test file with the surface deform modifier,
memory usage goes from 14 GB to 4 GB, and an annoying freeze
from preparing an undo step after every operation is gone.

Pull Request: https://projects.blender.org/blender/blender/pulls/145705
This commit is contained in:
Hans Goudey
2025-09-11 20:00:01 +02:00
committed by Hans Goudey
parent eccb7fddb0
commit a08cd68f1e
8 changed files with 281 additions and 149 deletions

View File

@@ -1577,6 +1577,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
{
using namespace blender;
MDefBindInfluence *inf;
MDefInfluence *mdinf;
MDefCell *cell;
@@ -1698,7 +1699,9 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
/* convert MDefBindInfluences to smaller MDefInfluences */
mmd->dyngrid = MEM_calloc_arrayN<MDefCell>(mdb->size3, "MDefDynGrid");
mmd->dyngrid_sharing_info = implicit_sharing::info_for_mem_free(mmd->dyngrid);
mmd->dyninfluences = MEM_calloc_arrayN<MDefInfluence>(mmd->influences_num, "MDefInfluence");
mmd->dyninfluences_sharing_info = implicit_sharing::info_for_mem_free(mmd->dyninfluences);
offset = 0;
for (a = 0; a < mdb->size3; a++) {
cell = &mmd->dyngrid[a];
@@ -1724,6 +1727,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
}
mmd->dynverts = mdb->inside;
mmd->dynverts_sharing_info = implicit_sharing::info_for_mem_free(mmd->dynverts);
mmd->dyngridsize = mdb->size;
copy_v3_v3(mmd->dyncellmin, mdb->min);
mmd->dyncellwidth = mdb->width[0];
@@ -1749,6 +1753,7 @@ void ED_mesh_deform_bind_callback(Object *object,
int verts_num,
float cagemat[4][4])
{
using namespace blender;
MeshDeformModifierData *mmd_orig = reinterpret_cast<MeshDeformModifierData *>(
BKE_modifier_get_original(object, &mmd->modifier));
MeshDeformBind mdb{};
@@ -1784,6 +1789,7 @@ void ED_mesh_deform_bind_callback(Object *object,
/* assign bind variables */
mmd_orig->bindcagecos = (float *)mdb.cagecos;
mmd_orig->bindcagecos_sharing_info = implicit_sharing::info_for_mem_free(mmd_orig->bindcagecos);
mmd_orig->verts_num = mdb.verts_num;
mmd_orig->cage_verts_num = mdb.cage_verts_num;
copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->object_to_world().ptr());

View File

@@ -28,6 +28,7 @@
#include "BLI_array_utils.hh"
#include "BLI_bitmap.h"
#include "BLI_implicit_sharing.hh"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
@@ -2941,7 +2942,7 @@ static wmOperatorStatus correctivesmooth_bind_exec(bContext *C, wmOperator *op)
const bool is_bind = (csmd->bind_coords != nullptr);
MEM_SAFE_FREE(csmd->bind_coords);
implicit_sharing::free_shared_data(&csmd->bind_coords, &csmd->bind_coords_sharing_info);
MEM_SAFE_FREE(csmd->delta_cache.deltas);
if (is_bind) {
@@ -3005,6 +3006,7 @@ static bool meshdeform_poll(bContext *C)
static wmOperatorStatus meshdeform_bind_exec(bContext *C, wmOperator *op)
{
using namespace blender;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = context_active_object(C);
MeshDeformModifierData *mmd = (MeshDeformModifierData *)edit_modifier_property_get(
@@ -3015,12 +3017,12 @@ static wmOperatorStatus meshdeform_bind_exec(bContext *C, wmOperator *op)
}
if (mmd->bindcagecos != nullptr) {
MEM_SAFE_FREE(mmd->bindcagecos);
MEM_SAFE_FREE(mmd->dyngrid);
MEM_SAFE_FREE(mmd->dyninfluences);
MEM_SAFE_FREE(mmd->bindinfluences);
MEM_SAFE_FREE(mmd->bindoffsets);
MEM_SAFE_FREE(mmd->dynverts);
implicit_sharing::free_shared_data(&mmd->bindcagecos, &mmd->bindcagecos_sharing_info);
implicit_sharing::free_shared_data(&mmd->dyngrid, &mmd->dyngrid_sharing_info);
implicit_sharing::free_shared_data(&mmd->dyninfluences, &mmd->dyninfluences_sharing_info);
implicit_sharing::free_shared_data(&mmd->bindinfluences, &mmd->bindinfluences_sharing_info);
implicit_sharing::free_shared_data(&mmd->bindoffsets, &mmd->bindoffsets_sharing_info);
implicit_sharing::free_shared_data(&mmd->dynverts, &mmd->dynverts_sharing_info);
MEM_SAFE_FREE(mmd->bindweights); /* Deprecated */
MEM_SAFE_FREE(mmd->bindcos); /* Deprecated */
mmd->verts_num = 0;
@@ -3367,10 +3369,13 @@ static wmOperatorStatus laplaciandeform_bind_exec(bContext *C, wmOperator *op)
* happening for binding or not. So we copy all the required data here. */
lmd->verts_num = lmd_eval->verts_num;
if (lmd_eval->vertexco == nullptr) {
MEM_SAFE_FREE(lmd->vertexco);
implicit_sharing::free_shared_data(&lmd->vertexco, &lmd->vertexco_sharing_info);
}
else {
lmd->vertexco = static_cast<float *>(MEM_dupallocN(lmd_eval->vertexco));
implicit_sharing::copy_shared_pointer(lmd_eval->vertexco,
lmd_eval->vertexco_sharing_info,
&lmd->vertexco,
&lmd->vertexco_sharing_info);
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);

View File

@@ -8,6 +8,7 @@
#pragma once
#include "BLI_implicit_sharing.h"
#include "BLI_utildefines.h"
#include "DNA_defs.h"
@@ -1069,20 +1070,26 @@ typedef struct MeshDeformModifierData {
/* result of static binding */
/** Influences. */
MDefInfluence *bindinfluences;
const ImplicitSharingInfoHandle *bindinfluences_sharing_info;
/** Offsets into influences array. */
int *bindoffsets;
const ImplicitSharingInfoHandle *bindoffsets_sharing_info;
/** Coordinates that cage was bound with. */
float *bindcagecos;
const ImplicitSharingInfoHandle *bindcagecos_sharing_info;
/** Total vertices in mesh and cage. */
int verts_num, cage_verts_num;
/* result of dynamic binding */
/** Grid with dynamic binding cell points. */
MDefCell *dyngrid;
const ImplicitSharingInfoHandle *dyngrid_sharing_info;
/** Dynamic binding vertex influences. */
MDefInfluence *dyninfluences;
const ImplicitSharingInfoHandle *dyninfluences_sharing_info;
/** Is this vertex bound or not? */
int *dynverts;
const ImplicitSharingInfoHandle *dynverts_sharing_info;
/** Size of the dynamic bind grid. */
int dyngridsize;
/** Total number of vertex influences. */
@@ -1969,6 +1976,7 @@ typedef struct CorrectiveSmoothModifierData {
/* positions set during 'bind' operator
* use for MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND */
float (*bind_coords)[3];
const ImplicitSharingInfoHandle *bind_coords_sharing_info;
/* NOTE: -1 is used to bind. */
unsigned int bind_coords_num;
@@ -2123,6 +2131,7 @@ typedef struct LaplacianDeformModifierData {
char anchor_grp_name[/*MAX_VGROUP_NAME*/ 64];
int verts_num, repeat;
float *vertexco;
const ImplicitSharingInfoHandle *vertexco_sharing_info;
/** Runtime only. */
void *cache_system;
/** #LaplacianDeformModifierFlag. */
@@ -2335,7 +2344,7 @@ typedef struct SurfaceDeformModifierData {
struct Object *target;
/** Vertex bind data. */
SDefVert *verts;
void *_pad1;
const ImplicitSharingInfoHandle *verts_sharing_info;
float falloff;
/* Number of vertices on the deformed mesh upon the bind process. */
unsigned int mesh_verts_num;

View File

@@ -1814,7 +1814,7 @@ static void rna_CorrectiveSmoothModifier_rest_source_update(Main *bmain,
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
if (csmd->rest_source != MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
MEM_SAFE_FREE(csmd->bind_coords);
blender::implicit_sharing::free_shared_data(&csmd, &csmd->bind_coords_sharing_info);
csmd->bind_coords_num = 0;
}

View File

@@ -67,9 +67,10 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
BKE_modifier_copydata_generic(md, target, flag);
if (csmd->bind_coords) {
tcsmd->bind_coords = static_cast<float(*)[3]>(MEM_dupallocN(csmd->bind_coords));
}
blender::implicit_sharing::copy_shared_pointer(csmd->bind_coords,
csmd->bind_coords_sharing_info,
&tcsmd->bind_coords,
&tcsmd->bind_coords_sharing_info);
tcsmd->delta_cache.deltas = nullptr;
tcsmd->delta_cache.deltas_num = 0;
@@ -77,7 +78,7 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
static void freeBind(CorrectiveSmoothModifierData *csmd)
{
MEM_SAFE_FREE(csmd->bind_coords);
blender::implicit_sharing::free_shared_data(&csmd->bind_coords, &csmd->bind_coords_sharing_info);
MEM_SAFE_FREE(csmd->delta_cache.deltas);
csmd->bind_coords_num = 0;
@@ -551,6 +552,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
blender::MutableSpan<blender::float3> vertexCos,
BMEditMesh *em)
{
using namespace blender;
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
const bool force_delta_cache_update =
@@ -575,13 +577,19 @@ static void correctivesmooth_modifier_do(ModifierData *md,
if (DEG_is_active(depsgraph)) {
BLI_assert(csmd->bind_coords == nullptr);
csmd->bind_coords = MEM_malloc_arrayN<float[3]>(size_t(vertexCos.size()), __func__);
csmd->bind_coords_sharing_info = implicit_sharing::info_for_mem_free(csmd->bind_coords);
memcpy(csmd->bind_coords, vertexCos.data(), size_t(vertexCos.size_in_bytes()));
csmd->bind_coords_num = uint(vertexCos.size());
BLI_assert(csmd->bind_coords != nullptr);
/* Copy bound data to the original modifier. */
CorrectiveSmoothModifierData *csmd_orig = (CorrectiveSmoothModifierData *)
BKE_modifier_get_original(ob, &csmd->modifier);
csmd_orig->bind_coords = static_cast<float(*)[3]>(MEM_dupallocN(csmd->bind_coords));
implicit_sharing::copy_shared_pointer(csmd->bind_coords,
csmd->bind_coords_sharing_info,
&csmd_orig->bind_coords,
&csmd_orig->bind_coords_sharing_info);
csmd_orig->bind_coords_num = csmd->bind_coords_num;
}
else {
@@ -780,13 +788,21 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
* binding data, can save a significant amount of memory. */
csmd.bind_coords_num = 0;
csmd.bind_coords = nullptr;
csmd.bind_coords_sharing_info = nullptr;
}
}
BLO_write_struct_at_address(writer, CorrectiveSmoothModifierData, md, &csmd);
if (csmd.bind_coords != nullptr) {
BLO_write_float3_array(writer, csmd.bind_coords_num, (float *)csmd.bind_coords);
BLO_write_shared(writer,
csmd.bind_coords,
sizeof(float[3]) * csmd.bind_coords_num,
csmd.bind_coords_sharing_info,
[&]() {
BLO_write_float3_array(
writer, csmd.bind_coords_num, (const float *)csmd.bind_coords);
});
}
}
@@ -795,7 +811,10 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
if (csmd->bind_coords) {
BLO_read_float3_array(reader, int(csmd->bind_coords_num), (float **)&csmd->bind_coords);
csmd->bind_coords_sharing_info = BLO_read_shared(reader, &csmd->bind_coords, [&]() {
BLO_read_float3_array(reader, int(csmd->bind_coords_num), (float **)&csmd->bind_coords);
return blender::implicit_sharing::info_for_mem_free(csmd->bind_coords);
});
}
/* runtime only */

View File

@@ -576,6 +576,7 @@ static void initSystem(
memcpy(sys->co, vertexCos, sizeof(float[3]) * verts_num);
MEM_freeN(index_anchors);
lmd->vertexco = MEM_malloc_arrayN<float>(3 * size_t(verts_num), __func__);
lmd->vertexco_sharing_info = blender::implicit_sharing::info_for_mem_free(lmd->vertexco);
memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * verts_num);
lmd->verts_num = verts_num;
@@ -702,7 +703,7 @@ static void LaplacianDeformModifier_do(
else if (lmd->verts_num > 0 && lmd->verts_num == verts_num) {
filevertexCos = MEM_malloc_arrayN<float[3]>(size_t(verts_num), "TempDeformCoordinates");
memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * verts_num);
MEM_SAFE_FREE(lmd->vertexco);
blender::implicit_sharing::free_shared_data(&lmd->vertexco, &lmd->vertexco_sharing_info);
lmd->verts_num = 0;
initSystem(lmd, ob, mesh, filevertexCos, verts_num);
sys = static_cast<LaplacianSystem *>(lmd->cache_system);
@@ -736,7 +737,8 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
BKE_modifier_copydata_generic(md, target, flag);
tlmd->vertexco = static_cast<float *>(MEM_dupallocN(lmd->vertexco));
blender::implicit_sharing::copy_shared_pointer(
lmd->vertexco, lmd->vertexco_sharing_info, &tlmd->vertexco, &tlmd->vertexco_sharing_info);
tlmd->cache_system = nullptr;
}
@@ -777,7 +779,7 @@ static void free_data(ModifierData *md)
if (sys) {
deleteLaplacianSystem(sys);
}
MEM_SAFE_FREE(lmd->vertexco);
blender::implicit_sharing::free_shared_data(&lmd->vertexco, &lmd->vertexco_sharing_info);
lmd->verts_num = 0;
}
@@ -826,13 +828,17 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
* binding data, can save a significant amount of memory. */
lmd.verts_num = 0;
lmd.vertexco = nullptr;
lmd.vertexco_sharing_info = nullptr;
}
}
BLO_write_struct_at_address(writer, LaplacianDeformModifierData, md, &lmd);
if (lmd.vertexco != nullptr) {
BLO_write_float3_array(writer, lmd.verts_num, lmd.vertexco);
BLO_write_shared(
writer, lmd.vertexco, sizeof(float[3]) * lmd.verts_num, lmd.vertexco_sharing_info, [&]() {
BLO_write_float3_array(writer, lmd.verts_num, lmd.vertexco);
});
}
}
@@ -840,7 +846,12 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
{
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
BLO_read_float3_array(reader, lmd->verts_num, &lmd->vertexco);
if (lmd->vertexco) {
lmd->vertexco_sharing_info = BLO_read_shared(reader, &lmd->vertexco, [&]() {
BLO_read_float3_array(reader, lmd->verts_num, &lmd->vertexco);
return blender::implicit_sharing::info_for_mem_free(lmd->vertexco);
});
}
lmd->cache_system = nullptr;
}

View File

@@ -52,26 +52,15 @@ static void init_data(ModifierData *md)
static void free_data(ModifierData *md)
{
using namespace blender;
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
if (mmd->bindinfluences) {
MEM_freeN(mmd->bindinfluences);
}
if (mmd->bindoffsets) {
MEM_freeN(mmd->bindoffsets);
}
if (mmd->bindcagecos) {
MEM_freeN(mmd->bindcagecos);
}
if (mmd->dyngrid) {
MEM_freeN(mmd->dyngrid);
}
if (mmd->dyninfluences) {
MEM_freeN(mmd->dyninfluences);
}
if (mmd->dynverts) {
MEM_freeN(mmd->dynverts);
}
implicit_sharing::free_shared_data(&mmd->bindinfluences, &mmd->bindinfluences_sharing_info);
implicit_sharing::free_shared_data(&mmd->bindoffsets, &mmd->bindoffsets_sharing_info);
implicit_sharing::free_shared_data(&mmd->bindcagecos, &mmd->bindcagecos_sharing_info);
implicit_sharing::free_shared_data(&mmd->dyngrid, &mmd->dyngrid_sharing_info);
implicit_sharing::free_shared_data(&mmd->dyninfluences, &mmd->dyninfluences_sharing_info);
implicit_sharing::free_shared_data(&mmd->dynverts, &mmd->dynverts_sharing_info);
if (mmd->bindweights) {
MEM_freeN(mmd->bindweights); /* deprecated */
}
@@ -82,29 +71,32 @@ static void free_data(ModifierData *md)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
{
using namespace blender;
const MeshDeformModifierData *mmd = (const MeshDeformModifierData *)md;
MeshDeformModifierData *tmmd = (MeshDeformModifierData *)target;
BKE_modifier_copydata_generic(md, target, flag);
if (mmd->bindinfluences) {
tmmd->bindinfluences = static_cast<MDefInfluence *>(MEM_dupallocN(mmd->bindinfluences));
}
if (mmd->bindoffsets) {
tmmd->bindoffsets = static_cast<int *>(MEM_dupallocN(mmd->bindoffsets));
}
if (mmd->bindcagecos) {
tmmd->bindcagecos = static_cast<float *>(MEM_dupallocN(mmd->bindcagecos));
}
if (mmd->dyngrid) {
tmmd->dyngrid = static_cast<MDefCell *>(MEM_dupallocN(mmd->dyngrid));
}
if (mmd->dyninfluences) {
tmmd->dyninfluences = static_cast<MDefInfluence *>(MEM_dupallocN(mmd->dyninfluences));
}
if (mmd->dynverts) {
tmmd->dynverts = static_cast<int *>(MEM_dupallocN(mmd->dynverts));
}
implicit_sharing::copy_shared_pointer(mmd->bindinfluences,
mmd->bindinfluences_sharing_info,
&tmmd->bindinfluences,
&tmmd->bindinfluences_sharing_info);
implicit_sharing::copy_shared_pointer(mmd->bindoffsets,
mmd->bindoffsets_sharing_info,
&tmmd->bindoffsets,
&tmmd->bindoffsets_sharing_info);
implicit_sharing::copy_shared_pointer(mmd->bindcagecos,
mmd->bindcagecos_sharing_info,
&tmmd->bindcagecos,
&tmmd->bindcagecos_sharing_info);
implicit_sharing::copy_shared_pointer(
mmd->dyngrid, mmd->dyngrid_sharing_info, &tmmd->dyngrid, &tmmd->dyngrid_sharing_info);
implicit_sharing::copy_shared_pointer(mmd->dyninfluences,
mmd->dyninfluences_sharing_info,
&tmmd->dyninfluences,
&tmmd->dyninfluences_sharing_info);
implicit_sharing::copy_shared_pointer(
mmd->dynverts, mmd->dynverts_sharing_info, &tmmd->dynverts, &tmmd->dynverts_sharing_info);
if (mmd->bindweights) {
tmmd->bindweights = static_cast<float *>(MEM_dupallocN(mmd->bindweights)); /* deprecated */
}
@@ -322,7 +314,7 @@ static void meshdeformModifier_do(ModifierData *md,
Mesh *cagemesh;
const MDeformVert *dvert = nullptr;
float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4];
float(*bindcagecos)[3];
const float(*bindcagecos)[3];
int a, cage_verts_num, defgrp_index;
MeshdeformUserdata data;
@@ -397,7 +389,7 @@ static void meshdeformModifier_do(ModifierData *md,
/* setup deformation data */
BKE_mesh_wrapper_vert_coords_copy(cagemesh, dco.as_mutable_span().take_front(cage_verts_num));
bindcagecos = (float(*)[3])mmd->bindcagecos;
bindcagecos = (const float(*)[3])mmd->bindcagecos;
for (a = 0; a < cage_verts_num; a++) {
/* Get cage vertex in world-space with binding transform. */
@@ -440,6 +432,7 @@ static void deform_verts(ModifierData *md,
void BKE_modifier_mdef_compact_influences(ModifierData *md)
{
using namespace blender;
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
float weight, totweight;
int influences_num, verts_num, cage_verts_num, a, b;
@@ -465,7 +458,9 @@ void BKE_modifier_mdef_compact_influences(ModifierData *md)
/* allocate bind influences */
mmd->bindinfluences = MEM_calloc_arrayN<MDefInfluence>(mmd->influences_num, __func__);
mmd->bindinfluences_sharing_info = implicit_sharing::info_for_mem_free(mmd->bindinfluences);
mmd->bindoffsets = MEM_calloc_arrayN<int>(size_t(verts_num) + 1, __func__);
mmd->bindoffsets_sharing_info = implicit_sharing::info_for_mem_free(mmd->bindoffsets);
/* write influences */
influences_num = 0;
@@ -548,15 +543,21 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
* binding data, can save a significant amount of memory. */
mmd.influences_num = 0;
mmd.bindinfluences = nullptr;
mmd.bindinfluences_sharing_info = nullptr;
mmd.verts_num = 0;
mmd.bindoffsets = nullptr;
mmd.bindoffsets_sharing_info = nullptr;
mmd.cage_verts_num = 0;
mmd.bindcagecos = nullptr;
mmd.bindcagecos_sharing_info = nullptr;
mmd.dyngridsize = 0;
mmd.dyngrid = nullptr;
mmd.dyngrid_sharing_info = nullptr;
mmd.influences_num = 0;
mmd.dyninfluences = nullptr;
mmd.dyninfluences_sharing_info = nullptr;
mmd.dynverts = nullptr;
mmd.dynverts_sharing_info = nullptr;
}
}
@@ -564,21 +565,50 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
BLO_write_struct_at_address(writer, MeshDeformModifierData, md, &mmd);
BLO_write_struct_array(writer, MDefInfluence, mmd.influences_num, mmd.bindinfluences);
BLO_write_shared(writer,
mmd.bindinfluences,
sizeof(MDefInfluence) * mmd.influences_num,
mmd.bindinfluences_sharing_info,
[&]() {
BLO_write_struct_array(
writer, MDefInfluence, mmd.influences_num, mmd.bindinfluences);
});
/* NOTE: `bindoffset` is abusing `verts_num + 1` as its size, this becomes an incorrect value in
* case `verts_num == 0`, since `bindoffset` is then nullptr, not a size 1 allocated array. */
if (mmd.verts_num > 0) {
BLO_write_int32_array(writer, mmd.verts_num + 1, mmd.bindoffsets);
BLO_write_shared(writer,
mmd.bindoffsets,
sizeof(int) * (mmd.verts_num + 1),
mmd.bindoffsets_sharing_info,
[&]() { BLO_write_int32_array(writer, mmd.verts_num + 1, mmd.bindoffsets); });
}
else {
BLI_assert(mmd.bindoffsets == nullptr);
}
BLO_write_float3_array(writer, mmd.cage_verts_num, mmd.bindcagecos);
BLO_write_struct_array(writer, MDefCell, size * size * size, mmd.dyngrid);
BLO_write_struct_array(writer, MDefInfluence, mmd.influences_num, mmd.dyninfluences);
BLO_write_int32_array(writer, mmd.verts_num, mmd.dynverts);
BLO_write_shared(writer,
mmd.bindcagecos,
sizeof(float[3]) * mmd.cage_verts_num,
mmd.bindcagecos_sharing_info,
[&]() { BLO_write_float3_array(writer, mmd.cage_verts_num, mmd.bindcagecos); });
BLO_write_shared(
writer, mmd.dyngrid, sizeof(MDefCell) * size * size * size, mmd.dyngrid_sharing_info, [&]() {
BLO_write_struct_array(writer, MDefCell, size * size * size, mmd.dyngrid);
});
BLO_write_shared(writer,
mmd.dyninfluences,
sizeof(MDefInfluence) * mmd.influences_num,
mmd.dyninfluences_sharing_info,
[&]() {
BLO_write_struct_array(
writer, MDefInfluence, mmd.influences_num, mmd.dyninfluences);
});
BLO_write_shared(writer,
mmd.dynverts,
sizeof(MDefInfluence) * mmd.verts_num,
mmd.dynverts_sharing_info,
[&]() { BLO_write_int32_array(writer, mmd.verts_num, mmd.dynverts); });
}
static void blend_read(BlendDataReader *reader, ModifierData *md)
@@ -586,18 +616,48 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
const int size = mmd->dyngridsize;
BLO_read_struct_array(reader, MDefInfluence, mmd->influences_num, &mmd->bindinfluences);
if (mmd->bindinfluences) {
mmd->bindinfluences_sharing_info = BLO_read_shared(reader, &mmd->bindinfluences, [&]() {
BLO_read_struct_array(reader, MDefInfluence, mmd->influences_num, &mmd->bindinfluences);
return blender::implicit_sharing::info_for_mem_free(mmd->bindinfluences);
});
}
/* NOTE: `bindoffset` is abusing `verts_num + 1` as its size, this becomes an incorrect value in
* case `verts_num == 0`, since `bindoffset` is then nullptr, not a size 1 allocated array. */
if (mmd->verts_num > 0) {
BLO_read_int32_array(reader, mmd->verts_num + 1, &mmd->bindoffsets);
if (mmd->bindoffsets) {
mmd->bindoffsets_sharing_info = BLO_read_shared(reader, &mmd->bindoffsets, [&]() {
BLO_read_int32_array(reader, mmd->verts_num + 1, &mmd->bindoffsets);
return blender::implicit_sharing::info_for_mem_free(mmd->bindoffsets);
});
}
}
BLO_read_float3_array(reader, mmd->cage_verts_num, &mmd->bindcagecos);
BLO_read_struct_array(reader, MDefCell, size * size * size, &mmd->dyngrid);
BLO_read_struct_array(reader, MDefInfluence, mmd->influences_num, &mmd->dyninfluences);
BLO_read_int32_array(reader, mmd->verts_num, &mmd->dynverts);
if (mmd->bindcagecos) {
mmd->bindcagecos_sharing_info = BLO_read_shared(reader, &mmd->bindcagecos, [&]() {
BLO_read_float3_array(reader, mmd->cage_verts_num, &mmd->bindcagecos);
return blender::implicit_sharing::info_for_mem_free(mmd->bindcagecos);
});
}
if (mmd->dyngrid) {
mmd->dyngrid_sharing_info = BLO_read_shared(reader, &mmd->dyngrid, [&]() {
BLO_read_struct_array(reader, MDefCell, size * size * size, &mmd->dyngrid);
return blender::implicit_sharing::info_for_mem_free(mmd->dyngrid);
});
}
if (mmd->dyninfluences) {
mmd->dyninfluences_sharing_info = BLO_read_shared(reader, &mmd->dyninfluences, [&]() {
BLO_read_struct_array(reader, MDefInfluence, mmd->influences_num, &mmd->dyninfluences);
return blender::implicit_sharing::info_for_mem_free(mmd->dyninfluences);
});
}
if (mmd->dynverts) {
mmd->dynverts_sharing_info = BLO_read_shared(reader, &mmd->dynverts, [&]() {
BLO_read_int32_array(reader, mmd->verts_num, &mmd->dynverts);
return blender::implicit_sharing::info_for_mem_free(mmd->dynverts);
});
}
/* Deprecated storage. */
BLO_read_float_array(reader, mmd->verts_num, &mmd->bindweights);

View File

@@ -208,23 +208,37 @@ static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_
}
}
class BindVertsImplicitSharing : public blender::ImplicitSharingInfo {
public:
SDefVert *verts;
int bind_verts_num;
BindVertsImplicitSharing(SDefVert *data, int bind_verts_num)
: verts(data), bind_verts_num(bind_verts_num)
{
}
private:
void delete_self_with_data() override
{
for (int i = 0; i < this->bind_verts_num; i++) {
if (this->verts[i].binds) {
for (int j = 0; j < this->verts[i].binds_num; j++) {
MEM_SAFE_FREE(this->verts[i].binds[j].vert_inds);
MEM_SAFE_FREE(this->verts[i].binds[j].vert_weights);
}
MEM_freeN(this->verts[i].binds);
}
}
MEM_freeN(verts);
MEM_delete(this);
}
};
static void free_data(ModifierData *md)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
if (smd->verts) {
for (int i = 0; i < smd->bind_verts_num; i++) {
if (smd->verts[i].binds) {
for (int j = 0; j < smd->verts[i].binds_num; j++) {
MEM_SAFE_FREE(smd->verts[i].binds[j].vert_inds);
MEM_SAFE_FREE(smd->verts[i].binds[j].vert_weights);
}
MEM_freeN(smd->verts[i].binds);
}
}
MEM_SAFE_FREE(smd->verts);
}
blender::implicit_sharing::free_shared_data(&smd->verts, &smd->verts_sharing_info);
}
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
@@ -234,27 +248,8 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
BKE_modifier_copydata_generic(md, target, flag);
if (smd->verts) {
tsmd->verts = static_cast<SDefVert *>(MEM_dupallocN(smd->verts));
for (int i = 0; i < smd->bind_verts_num; i++) {
if (smd->verts[i].binds) {
tsmd->verts[i].binds = static_cast<SDefBind *>(MEM_dupallocN(smd->verts[i].binds));
for (int j = 0; j < smd->verts[i].binds_num; j++) {
if (smd->verts[i].binds[j].vert_inds) {
tsmd->verts[i].binds[j].vert_inds = static_cast<uint *>(
MEM_dupallocN(smd->verts[i].binds[j].vert_inds));
}
if (smd->verts[i].binds[j].vert_weights) {
tsmd->verts[i].binds[j].vert_weights = static_cast<float *>(
MEM_dupallocN(smd->verts[i].binds[j].vert_weights));
}
}
}
}
}
blender::implicit_sharing::copy_shared_pointer(
smd->verts, smd->verts_sharing_info, &tsmd->verts, &tsmd->verts_sharing_info);
}
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
@@ -1147,12 +1142,26 @@ static void compactSparseBinds(SurfaceDeformModifierData *smd)
for (uint i = 0; i < smd->mesh_verts_num; i++) {
if (smd->verts[i].binds_num > 0) {
smd->verts[smd->bind_verts_num++] = smd->verts[i];
smd->bind_verts_num++;
}
}
smd->verts = static_cast<SDefVert *>(MEM_reallocN_id(
smd->verts, sizeof(*smd->verts) * smd->bind_verts_num, "SDefBindVerts (sparse)"));
SDefVert *new_verts = MEM_malloc_arrayN<SDefVert>(size_t(smd->bind_verts_num), __func__);
/* Move data to new_verts. */
BLI_assert(smd->verts_sharing_info->is_mutable());
int dst_index = 0;
for (uint i = 0; i < smd->mesh_verts_num; i++) {
if (smd->verts[i].binds_num > 0) {
new_verts[dst_index++] = smd->verts[i];
smd->verts[i] = {};
}
}
smd->verts_sharing_info->remove_user_and_delete_if_last();
smd->verts = new_verts;
smd->verts_sharing_info = MEM_new<BindVertsImplicitSharing>(
__func__, smd->verts, smd->bind_verts_num);
}
static bool surfacedeformBind(Object *ob,
@@ -1165,6 +1174,7 @@ static bool surfacedeformBind(Object *ob,
Mesh *target,
Mesh *mesh)
{
using namespace blender;
const blender::Span<blender::float3> positions = target->vert_positions();
const blender::Span<blender::int2> edges = target->edges();
const blender::OffsetIndices polys = target->faces();
@@ -1202,13 +1212,14 @@ static bool surfacedeformBind(Object *ob,
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
return false;
}
smd_orig->verts_sharing_info = MEM_new<BindVertsImplicitSharing>(
__func__, smd_orig->verts, verts_num);
blender::bke::BVHTreeFromMesh treeData = target->bvh_corner_tris();
if (treeData.tree == nullptr) {
BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
MEM_freeN(smd_orig->verts);
smd_orig->verts = nullptr;
implicit_sharing::free_shared_data(&smd_orig->verts, &smd_orig->verts_sharing_info);
return false;
}
@@ -1218,8 +1229,7 @@ static bool surfacedeformBind(Object *ob,
BKE_modifier_set_error(
ob, (ModifierData *)smd_eval, "Target has edges with more than two polygons");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
MEM_freeN(smd_orig->verts);
smd_orig->verts = nullptr;
implicit_sharing::free_shared_data(&smd_orig->verts, &smd_orig->verts_sharing_info);
return false;
}
@@ -1633,34 +1643,41 @@ static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierD
* binding data, can save a significant amount of memory. */
smd.bind_verts_num = 0;
smd.verts = nullptr;
smd.verts_sharing_info = nullptr;
}
}
BLO_write_struct_at_address(writer, SurfaceDeformModifierData, md, &smd);
if (smd.verts != nullptr) {
SDefVert *bind_verts = smd.verts;
BLO_write_struct_array(writer, SDefVert, smd.bind_verts_num, bind_verts);
BLO_write_shared(
writer, smd.verts, sizeof(SDefVert) * smd.bind_verts_num, smd.verts_sharing_info, [&]() {
SDefVert *bind_verts = smd.verts;
BLO_write_struct_array(writer, SDefVert, smd.bind_verts_num, bind_verts);
for (int i = 0; i < smd.bind_verts_num; i++) {
BLO_write_struct_array(writer, SDefBind, bind_verts[i].binds_num, bind_verts[i].binds);
for (int i = 0; i < smd.bind_verts_num; i++) {
BLO_write_struct_array(writer, SDefBind, bind_verts[i].binds_num, bind_verts[i].binds);
if (bind_verts[i].binds) {
for (int j = 0; j < bind_verts[i].binds_num; j++) {
BLO_write_uint32_array(
writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_inds);
if (bind_verts[i].binds) {
for (int j = 0; j < bind_verts[i].binds_num; j++) {
BLO_write_uint32_array(
writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_inds);
if (ELEM(bind_verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_CORNER_TRIS))
{
BLO_write_float3_array(writer, 1, bind_verts[i].binds[j].vert_weights);
if (ELEM(bind_verts[i].binds[j].mode,
MOD_SDEF_MODE_CENTROID,
MOD_SDEF_MODE_CORNER_TRIS))
{
BLO_write_float3_array(writer, 1, bind_verts[i].binds[j].vert_weights);
}
else {
BLO_write_float_array(writer,
bind_verts[i].binds[j].verts_num,
bind_verts[i].binds[j].vert_weights);
}
}
}
}
else {
BLO_write_float_array(
writer, bind_verts[i].binds[j].verts_num, bind_verts[i].binds[j].vert_weights);
}
}
}
}
});
}
}
@@ -1668,28 +1685,33 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
BLO_read_struct_array(reader, SDefVert, smd->bind_verts_num, &smd->verts);
if (smd->verts) {
for (int i = 0; i < smd->bind_verts_num; i++) {
BLO_read_struct_array(reader, SDefBind, smd->verts[i].binds_num, &smd->verts[i].binds);
smd->verts_sharing_info = BLO_read_shared(reader, &smd->verts, [&]() {
BLO_read_struct_array(reader, SDefVert, smd->bind_verts_num, &smd->verts);
for (int i = 0; i < smd->bind_verts_num; i++) {
BLO_read_struct_array(reader, SDefBind, smd->verts[i].binds_num, &smd->verts[i].binds);
if (smd->verts[i].binds) {
for (int j = 0; j < smd->verts[i].binds_num; j++) {
BLO_read_uint32_array(
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_inds);
if (smd->verts[i].binds) {
for (int j = 0; j < smd->verts[i].binds_num; j++) {
BLO_read_uint32_array(
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_inds);
if (ELEM(smd->verts[i].binds[j].mode, MOD_SDEF_MODE_CENTROID, MOD_SDEF_MODE_CORNER_TRIS))
{
BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights);
}
else {
BLO_read_float_array(
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_weights);
if (ELEM(smd->verts[i].binds[j].mode,
MOD_SDEF_MODE_CENTROID,
MOD_SDEF_MODE_CORNER_TRIS))
{
BLO_read_float3_array(reader, 1, &smd->verts[i].binds[j].vert_weights);
}
else {
BLO_read_float_array(
reader, smd->verts[i].binds[j].verts_num, &smd->verts[i].binds[j].vert_weights);
}
}
}
}
}
return MEM_new<BindVertsImplicitSharing>(
"BindVertsImplicitSharing", smd->verts, smd->bind_verts_num);
});
}
}