Fix T78650: Lattice evaluation writes to shared data

Fix the data management bug where evaluation of lattice objects would
write back to the CoW copy of the Lattice ID, even when that copy was
shared between objects.

Each lattice object evaluation now stores its own evaluated data copy
via `BKE_object_eval_assign_data()`.

Reviewed By: sergey

Maniphest Tasks: T78650

Differential Revision: https://developer.blender.org/D10790
This commit is contained in:
Sybren A. Stüvel 2021-03-29 10:14:53 +02:00
parent 8034b276ba
commit 3681a619de
Notes: blender-bot 2023-02-14 08:47:25 +01:00
Referenced by issue #87056, Segfault in GPU_batch_clear() involing Lattice evaluation
Referenced by issue #78650, Lattice objects evaluation is not properly decoupled when they share the same Lattice obdata.
5 changed files with 60 additions and 45 deletions

View File

@ -336,6 +336,12 @@ struct Mesh *BKE_object_get_evaluated_mesh(struct Object *object);
struct Mesh *BKE_object_get_pre_modified_mesh(struct Object *object);
struct Mesh *BKE_object_get_original_mesh(struct Object *object);
/* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice,
* whichever is currently in use. */
struct Lattice *BKE_object_get_lattice(const struct Object *object);
struct Lattice *BKE_object_get_evaluated_lattice(const struct Object *object);
int BKE_object_insert_ptcache(struct Object *ob);
void BKE_object_delete_ptcache(struct Object *ob, int index);
struct KeyBlock *BKE_object_shapekey_insert(struct Main *bmain,

View File

@ -540,10 +540,12 @@ void BKE_lattice_vert_coords_apply(Lattice *lt, const float (*vert_coords)[3])
void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
BKE_object_free_derived_caches(ob);
if (ob->runtime.curve_cache == NULL) {
ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
}
Lattice *lt = ob->data;
/* Get vertex coordinates from the original copy;
* otherwise we get already-modified coordinates. */
Object *ob_orig = DEG_get_original_object(ob);
VirtualModifierData virtualModifierData;
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
float(*vert_coords)[3] = NULL;
@ -551,13 +553,6 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
const bool is_editmode = (lt->editlatt != NULL);
const ModifierEvalContext mectx = {depsgraph, ob, 0};
if (ob->runtime.curve_cache) {
BKE_displist_free(&ob->runtime.curve_cache->disp);
}
else {
ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
}
for (; md; md = md->next) {
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
@ -577,49 +572,33 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
continue;
}
if (!vert_coords) {
Lattice *lt_orig = ob_orig->data;
if (lt_orig->editlatt) {
lt_orig = lt_orig->editlatt->latt;
}
vert_coords = BKE_lattice_vert_coords_alloc(lt_orig, &numVerts);
if (vert_coords == NULL) {
/* Get either the edit-mode or regular lattice, whichever is in use now. */
const Lattice *effective_lattice = BKE_object_get_lattice(ob);
vert_coords = BKE_lattice_vert_coords_alloc(effective_lattice, &numVerts);
}
mti->deformVerts(md, &mectx, NULL, vert_coords, numVerts);
}
if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) {
if (vert_coords) {
BKE_lattice_vert_coords_apply(ob->data, vert_coords);
MEM_freeN(vert_coords);
}
if (vert_coords == NULL) {
return;
}
else {
/* Displist won't do anything; this is just for posterity's sake until we remove it. */
if (!vert_coords) {
Lattice *lt_orig = ob_orig->data;
if (lt_orig->editlatt) {
lt_orig = lt_orig->editlatt->latt;
}
vert_coords = BKE_lattice_vert_coords_alloc(lt_orig, &numVerts);
}
DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
dl->type = DL_VERTS;
dl->parts = 1;
dl->nr = numVerts;
dl->verts = (float *)vert_coords;
BLI_addtail(&ob->runtime.curve_cache->disp, dl);
Lattice *lt_eval = BKE_object_get_evaluated_lattice(ob);
if (lt_eval == NULL) {
BKE_id_copy_ex(NULL, &lt->id, (ID **)&lt_eval, LIB_ID_COPY_LOCALIZE);
BKE_object_eval_assign_data(ob, &lt_eval->id, true);
}
BKE_lattice_vert_coords_apply(lt_eval, vert_coords);
MEM_freeN(vert_coords);
}
struct MDeformVert *BKE_lattice_deform_verts_get(const struct Object *oblatt)
{
Lattice *lt = (Lattice *)oblatt->data;
BLI_assert(oblatt->type == OB_LATTICE);
if (lt->editlatt) {
lt = lt->editlatt->latt;
}
Lattice *lt = BKE_object_get_lattice(oblatt);
return lt->dvert;
}

View File

@ -47,6 +47,7 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_deform.h"
@ -69,7 +70,7 @@ typedef struct LatticeDeformData {
LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Object *ob)
{
/* we make an array with all differences */
Lattice *lt = oblatt->data;
Lattice *lt = BKE_object_get_lattice(oblatt);
BPoint *bp;
DispList *dl = oblatt->runtime.curve_cache ?
BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) :
@ -83,9 +84,6 @@ LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Ob
float latmat[4][4];
LatticeDeformData *lattice_deform_data;
if (lt->editlatt) {
lt = lt->editlatt->latt;
}
bp = lt->def;
const int32_t num_points = lt->pntsu * lt->pntsv * lt->pntsw;

View File

@ -51,6 +51,7 @@ static void test_lattice_deform_init(LatticeDeformTestContext *ctx,
ctx->coords[index][2] = (rng->get_float() - 0.5f) * 10;
}
IDType_ID_LT.init_data(&ctx->lattice.id);
strcpy(ctx->lattice.id.name, "LTLattice");
IDType_ID_OB.init_data(&ctx->ob_lattice.id);
ctx->ob_lattice.type = OB_LATTICE;
ctx->ob_lattice.data = &ctx->lattice;

View File

@ -4474,6 +4474,37 @@ Mesh *BKE_object_get_original_mesh(Object *object)
return result;
}
Lattice *BKE_object_get_lattice(const Object *object)
{
ID *data = object->data;
if (data == NULL || GS(data->name) != ID_LT) {
return NULL;
}
Lattice *lt = (Lattice *)data;
if (lt->editlatt) {
return lt->editlatt->latt;
}
return lt;
}
Lattice *BKE_object_get_evaluated_lattice(const Object *object)
{
ID *data_eval = object->runtime.data_eval;
if (data_eval == NULL || GS(data_eval->name) != ID_LT) {
return NULL;
}
Lattice *lt_eval = (Lattice *)data_eval;
if (lt_eval->editlatt) {
return lt_eval->editlatt->latt;
}
return lt_eval;
}
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = a, *bd = b;