Fix T88026: Repeated switch to rendered viewport crashes
Resolve ownership ambiguity with shared physics pointers. Previously, LIB_ID_CREATE_NO_MAIN allowed pointer sharing with the source ID so physics caches can be shared between original and evaluated data: (Object.soft.shared & Object.rigidbody_object.shared). This only worked properly for LIB_TAG_COPIED_ON_WRITE ID's, as LIB_TAG_NO_MAIN can be used in situations where the original ID's lifetime limited by it's original data. This commit adds `LIB_ID_COPY_SET_COPIED_ON_WRITE` so ID's only share memory with original data for ID's evaluated in the depsgraph. For all other uses, a full copy of physics data is made. Ref D11228#287094
This commit is contained in:
parent
cdc1ddf20b
commit
dfb963c70d
Notes:
blender-bot
2023-02-14 06:00:51 +01:00
Referenced by commit 2a09634d41
, Fix particlesystem not duplicating their pointcache in NO_MAIN case.
Referenced by issue #88307, Crash when rendering Crurve with Softbody combined with Freestyle
Referenced by issue #88026, Repeated switch to Rendered viewport mode causes crash
|
@ -104,6 +104,10 @@ enum {
|
|||
* specific code in some copy cases (mostly for node trees). */
|
||||
LIB_ID_CREATE_LOCAL = 1 << 9,
|
||||
|
||||
/** Create for the depsgraph, when set #LIB_TAG_COPIED_ON_WRITE must be set.
|
||||
* Internally this is used to share some pointers instead of duplicating them. */
|
||||
LIB_ID_COPY_SET_COPIED_ON_WRITE = 1 << 10,
|
||||
|
||||
/* *** Specific options to some ID types or usages. *** */
|
||||
/* *** May be ignored by unrelated ID copying functions. *** */
|
||||
/** Object only, needed by make_local code. */
|
||||
|
|
|
@ -1245,6 +1245,13 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
|
|||
}
|
||||
BLI_assert(new_id != NULL);
|
||||
|
||||
if ((flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) != 0) {
|
||||
new_id->tag |= LIB_TAG_COPIED_ON_WRITE;
|
||||
}
|
||||
else {
|
||||
new_id->tag &= ~LIB_TAG_COPIED_ON_WRITE;
|
||||
}
|
||||
|
||||
const size_t id_len = BKE_libblock_get_alloc_info(GS(new_id->name), NULL);
|
||||
const size_t id_offset = sizeof(ID);
|
||||
if ((int)id_len - (int)id_offset > 0) { /* signed to allow neg result */ /* XXX ????? */
|
||||
|
|
|
@ -2292,7 +2292,7 @@ Object *BKE_object_add_for_data(
|
|||
void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src, const int flag)
|
||||
{
|
||||
SoftBody *sb = ob_src->soft;
|
||||
bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN;
|
||||
const bool is_orig = (flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) == 0;
|
||||
|
||||
ob_dst->softflag = ob_src->softflag;
|
||||
if (sb == NULL) {
|
||||
|
@ -2333,7 +2333,7 @@ void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src, const int fl
|
|||
|
||||
sbn->scratch = NULL;
|
||||
|
||||
if (!tagged_no_main) {
|
||||
if (is_orig) {
|
||||
sbn->shared = MEM_dupallocN(sb->shared);
|
||||
sbn->shared->pointcache = BKE_ptcache_copy_list(
|
||||
&sbn->shared->ptcaches, &sb->shared->ptcaches, flag);
|
||||
|
|
|
@ -260,10 +260,12 @@ static RigidBodyOb *rigidbody_copy_object(const Object *ob, const int flag)
|
|||
RigidBodyOb *rboN = NULL;
|
||||
|
||||
if (ob->rigidbody_object) {
|
||||
const bool is_orig = (flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) == 0;
|
||||
|
||||
/* just duplicate the whole struct first (to catch all the settings) */
|
||||
rboN = MEM_dupallocN(ob->rigidbody_object);
|
||||
|
||||
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
||||
if (is_orig) {
|
||||
/* This is a regular copy, and not a CoW copy for depsgraph evaluation */
|
||||
rboN->shared = MEM_callocN(sizeof(*rboN->shared), "RigidBodyOb_Shared");
|
||||
}
|
||||
|
|
|
@ -304,7 +304,8 @@ bool id_copy_inplace_no_main(const ID *id, ID *newid)
|
|||
bool result = (BKE_id_copy_ex(nullptr,
|
||||
(ID *)id_for_copy,
|
||||
&newid,
|
||||
LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE) != nullptr);
|
||||
(LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE |
|
||||
LIB_ID_COPY_SET_COPIED_ON_WRITE)) != nullptr);
|
||||
|
||||
#ifdef NESTED_ID_NASTY_WORKAROUND
|
||||
if (result) {
|
||||
|
@ -333,7 +334,8 @@ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene)
|
|||
bool result = (BKE_id_copy_ex(nullptr,
|
||||
id_for_copy,
|
||||
(ID **)&new_scene,
|
||||
LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE) != nullptr);
|
||||
(LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE |
|
||||
LIB_ID_COPY_SET_COPIED_ON_WRITE)) != nullptr);
|
||||
|
||||
#ifdef NESTED_ID_NASTY_WORKAROUND
|
||||
if (result) {
|
||||
|
|
|
@ -555,8 +555,15 @@ enum {
|
|||
/* RESET_AFTER_USE tag existing data before linking so we know what is new. */
|
||||
LIB_TAG_PRE_EXISTING = 1 << 11,
|
||||
|
||||
/* The data-block is a copy-on-write/localized version. */
|
||||
/**
|
||||
* The data-block is a copy-on-write/localized version.
|
||||
*
|
||||
* \warning This should not be cleared on existing data.
|
||||
* If support for this is needed, see T88026 as this flag controls memory ownership
|
||||
* of physics *shared* pointers.
|
||||
*/
|
||||
LIB_TAG_COPIED_ON_WRITE = 1 << 12,
|
||||
|
||||
LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT = 1 << 13,
|
||||
LIB_TAG_LOCALIZED = 1 << 14,
|
||||
|
||||
|
|
Loading…
Reference in New Issue