Refactor: Simplify undo object list creation, use C++ Vector
Replace the use of the `LIB_TAG_DOIT` flag which cwas used to only process each object data ID once with a Set. Return the objects or bases in a Vector. Now we only iterate over the view layers bases once instead of three times. Pull Request: https://projects.blender.org/blender/blender/pulls/119788
This commit is contained in:
@@ -221,15 +221,14 @@ static bool armature_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_
|
||||
* outside of this list will be moved out of edit-mode when reading back undo steps. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
uint objects_len = 0;
|
||||
Object **objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer, &objects_len);
|
||||
blender::Vector<Object *> objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer);
|
||||
|
||||
us->scene_ref.ptr = scene;
|
||||
us->elems = static_cast<ArmatureUndoStep_Elem *>(
|
||||
MEM_callocN(sizeof(*us->elems) * objects_len, __func__));
|
||||
us->elems_len = objects_len;
|
||||
MEM_callocN(sizeof(*us->elems) * objects.size(), __func__));
|
||||
us->elems_len = objects.size();
|
||||
|
||||
for (uint i = 0; i < objects_len; i++) {
|
||||
for (uint i = 0; i < objects.size(); i++) {
|
||||
Object *ob = objects[i];
|
||||
ArmatureUndoStep_Elem *elem = &us->elems[i];
|
||||
|
||||
@@ -239,7 +238,6 @@ static bool armature_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_
|
||||
arm->needs_flush_to_id = 1;
|
||||
us->step.data_size += elem->data.undo_size;
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
bmain->is_memfile_undo_flush_needed = true;
|
||||
|
||||
|
||||
@@ -210,15 +210,14 @@ static bool curve_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
* outside of this list will be moved out of edit-mode when reading back undo steps. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
uint objects_len = 0;
|
||||
Object **objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer, &objects_len);
|
||||
blender::Vector<Object *> objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer);
|
||||
|
||||
us->scene_ref.ptr = scene;
|
||||
us->elems = static_cast<CurveUndoStep_Elem *>(
|
||||
MEM_callocN(sizeof(*us->elems) * objects_len, __func__));
|
||||
us->elems_len = objects_len;
|
||||
MEM_callocN(sizeof(*us->elems) * objects.size(), __func__));
|
||||
us->elems_len = objects.size();
|
||||
|
||||
for (uint i = 0; i < objects_len; i++) {
|
||||
for (uint i = 0; i < objects.size(); i++) {
|
||||
Object *ob = objects[i];
|
||||
Curve *cu = static_cast<Curve *>(ob->data);
|
||||
CurveUndoStep_Elem *elem = &us->elems[i];
|
||||
@@ -228,7 +227,6 @@ static bool curve_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
cu->editnurb->needs_flush_to_id = 1;
|
||||
us->step.data_size += elem->data.undo_size;
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
bmain->is_memfile_undo_flush_needed = true;
|
||||
|
||||
|
||||
@@ -54,11 +54,10 @@ static bool step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
uint objects_num = 0;
|
||||
Object **objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer, &objects_num);
|
||||
Vector<Object *> objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer);
|
||||
|
||||
us->scene_ref.ptr = scene;
|
||||
new (&us->objects) Array<StepObject>(objects_num);
|
||||
new (&us->objects) Array<StepObject>(objects.size());
|
||||
|
||||
threading::parallel_for(us->objects.index_range(), 8, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
@@ -70,7 +69,6 @@ static bool step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
object.geometry = curves_id.geometry.wrap();
|
||||
}
|
||||
});
|
||||
MEM_SAFE_FREE(objects);
|
||||
|
||||
bmain->is_memfile_undo_flush_needed = true;
|
||||
|
||||
|
||||
@@ -337,12 +337,10 @@ static bool step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
uint objects_num = 0;
|
||||
Object **objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer, &objects_num);
|
||||
BLI_SCOPED_DEFER([&]() { MEM_SAFE_FREE(objects); })
|
||||
Vector<Object *> objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer);
|
||||
|
||||
us->scene_ref.ptr = scene;
|
||||
new (&us->objects) Array<StepObject>(objects_num);
|
||||
new (&us->objects) Array<StepObject>(objects.size());
|
||||
|
||||
threading::parallel_for(us->objects.index_range(), 8, [&](const IndexRange range) {
|
||||
for (const int64_t i : range) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_sys_types.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
struct Base;
|
||||
struct CLG_LogRef;
|
||||
@@ -101,12 +102,10 @@ void ED_undo_object_editmode_restore_helper(Scene *scene,
|
||||
uint object_array_len,
|
||||
uint object_array_stride);
|
||||
|
||||
Object **ED_undo_editmode_objects_from_view_layer(const Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
uint *r_len);
|
||||
Base **ED_undo_editmode_bases_from_view_layer(const Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
uint *r_len);
|
||||
blender::Vector<Object *> ED_undo_editmode_objects_from_view_layer(const Scene *scene,
|
||||
ViewLayer *view_layer);
|
||||
blender::Vector<Base *> ED_undo_editmode_bases_from_view_layer(const Scene *scene,
|
||||
ViewLayer *view_layer);
|
||||
|
||||
/**
|
||||
* Ideally we won't access the stack directly,
|
||||
|
||||
@@ -204,15 +204,14 @@ static bool lattice_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p
|
||||
* outside of this list will be moved out of edit-mode when reading back undo steps. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
uint objects_len = 0;
|
||||
Object **objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer, &objects_len);
|
||||
blender::Vector<Object *> objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer);
|
||||
|
||||
us->scene_ref.ptr = scene;
|
||||
us->elems = static_cast<LatticeUndoStep_Elem *>(
|
||||
MEM_callocN(sizeof(*us->elems) * objects_len, __func__));
|
||||
us->elems_len = objects_len;
|
||||
MEM_callocN(sizeof(*us->elems) * objects.size(), __func__));
|
||||
us->elems_len = objects.size();
|
||||
|
||||
for (uint i = 0; i < objects_len; i++) {
|
||||
for (uint i = 0; i < objects.size(); i++) {
|
||||
Object *ob = objects[i];
|
||||
LatticeUndoStep_Elem *elem = &us->elems[i];
|
||||
|
||||
@@ -222,7 +221,6 @@ static bool lattice_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p
|
||||
lt->editlatt->needs_flush_to_id = 1;
|
||||
us->step.data_size += elem->data.undo_size;
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
bmain->is_memfile_undo_flush_needed = true;
|
||||
|
||||
|
||||
@@ -928,21 +928,20 @@ static bool mesh_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
const ToolSettings *ts = scene->toolsettings;
|
||||
uint objects_len = 0;
|
||||
Object **objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer, &objects_len);
|
||||
blender::Vector<Object *> objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer);
|
||||
|
||||
us->scene_ref.ptr = scene;
|
||||
us->elems = static_cast<MeshUndoStep_Elem *>(
|
||||
MEM_callocN(sizeof(*us->elems) * objects_len, __func__));
|
||||
us->elems_len = objects_len;
|
||||
MEM_callocN(sizeof(*us->elems) * objects.size(), __func__));
|
||||
us->elems_len = objects.size();
|
||||
|
||||
UndoMesh **um_references = nullptr;
|
||||
|
||||
#ifdef USE_ARRAY_STORE
|
||||
um_references = mesh_undostep_reference_elems_from_objects(objects, objects_len);
|
||||
um_references = mesh_undostep_reference_elems_from_objects(objects.data(), objects.size());
|
||||
#endif
|
||||
|
||||
for (uint i = 0; i < objects_len; i++) {
|
||||
for (uint i = 0; i < objects.size(); i++) {
|
||||
Object *ob = objects[i];
|
||||
MeshUndoStep_Elem *elem = &us->elems[i];
|
||||
|
||||
@@ -962,7 +961,6 @@ static bool mesh_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
elem->data.mesh.id.session_uid = mesh->id.session_uid;
|
||||
#endif
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
if (um_references != nullptr) {
|
||||
MEM_freeN(um_references);
|
||||
|
||||
@@ -160,15 +160,14 @@ static bool mball_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
* outside of this list will be moved out of edit-mode when reading back undo steps. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
uint objects_len = 0;
|
||||
Object **objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer, &objects_len);
|
||||
blender::Vector<Object *> objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer);
|
||||
|
||||
us->scene_ref.ptr = scene;
|
||||
us->elems = static_cast<MBallUndoStep_Elem *>(
|
||||
MEM_callocN(sizeof(*us->elems) * objects_len, __func__));
|
||||
us->elems_len = objects_len;
|
||||
MEM_callocN(sizeof(*us->elems) * objects.size(), __func__));
|
||||
us->elems_len = objects.size();
|
||||
|
||||
for (uint i = 0; i < objects_len; i++) {
|
||||
for (uint i = 0; i < objects.size(); i++) {
|
||||
Object *ob = objects[i];
|
||||
MBallUndoStep_Elem *elem = &us->elems[i];
|
||||
|
||||
@@ -178,7 +177,6 @@ static bool mball_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
mb->needs_flush_to_id = 1;
|
||||
us->step.data_size += elem->data.undo_size;
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
bmain->is_memfile_undo_flush_needed = true;
|
||||
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
using blender::Set;
|
||||
using blender::Vector;
|
||||
|
||||
/** We only need this locally. */
|
||||
static CLG_LogRef LOG = {"ed.undo"};
|
||||
|
||||
@@ -852,12 +855,11 @@ void ED_undo_object_editmode_restore_helper(Scene *scene,
|
||||
uint object_array_stride)
|
||||
{
|
||||
Main *bmain = G_MAIN;
|
||||
uint bases_len = 0;
|
||||
/* Don't request unique data because we want to de-select objects when exiting edit-mode
|
||||
* for that to be done on all objects we can't skip ones that share data. */
|
||||
Base **bases = ED_undo_editmode_bases_from_view_layer(scene, view_layer, &bases_len);
|
||||
for (uint i = 0; i < bases_len; i++) {
|
||||
((ID *)bases[i]->object->data)->tag |= LIB_TAG_DOIT;
|
||||
Vector<Base *> bases = ED_undo_editmode_bases_from_view_layer(scene, view_layer);
|
||||
for (Base *base : bases) {
|
||||
((ID *)base->object->data)->tag |= LIB_TAG_DOIT;
|
||||
}
|
||||
Object **ob_p = object_array;
|
||||
for (uint i = 0; i < object_array_len;
|
||||
@@ -867,16 +869,15 @@ void ED_undo_object_editmode_restore_helper(Scene *scene,
|
||||
ED_object_editmode_enter_ex(bmain, scene, obedit, EM_NO_CONTEXT);
|
||||
((ID *)obedit->data)->tag &= ~LIB_TAG_DOIT;
|
||||
}
|
||||
for (uint i = 0; i < bases_len; i++) {
|
||||
ID *id = static_cast<ID *>(bases[i]->object->data);
|
||||
for (Base *base : bases) {
|
||||
ID *id = static_cast<ID *>(base->object->data);
|
||||
if (id->tag & LIB_TAG_DOIT) {
|
||||
ED_object_editmode_exit_ex(bmain, scene, bases[i]->object, EM_FREEDATA);
|
||||
ED_object_editmode_exit_ex(bmain, scene, base->object, EM_FREEDATA);
|
||||
/* Ideally we would know the selection state it was before entering edit-mode,
|
||||
* for now follow the convention of having them unselected when exiting the mode. */
|
||||
ED_object_base_select(bases[i], BA_DESELECT);
|
||||
ED_object_base_select(base, BA_DESELECT);
|
||||
}
|
||||
}
|
||||
MEM_freeN(bases);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -891,49 +892,17 @@ void ED_undo_object_editmode_restore_helper(Scene *scene,
|
||||
* and local collections may be used.
|
||||
* \{ */
|
||||
|
||||
static int undo_editmode_objects_from_view_layer_prepare(const Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
Object *obact)
|
||||
{
|
||||
const short object_type = obact->type;
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
ListBase *object_bases = BKE_view_layer_object_bases_get(view_layer);
|
||||
LISTBASE_FOREACH (Base *, base, object_bases) {
|
||||
Object *ob = base->object;
|
||||
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
|
||||
ID *id = static_cast<ID *>(ob->data);
|
||||
id->tag &= ~LIB_TAG_DOIT;
|
||||
}
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
LISTBASE_FOREACH (Base *, base, object_bases) {
|
||||
Object *ob = base->object;
|
||||
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
|
||||
ID *id = static_cast<ID *>(ob->data);
|
||||
if ((id->tag & LIB_TAG_DOIT) == 0) {
|
||||
len += 1;
|
||||
id->tag |= LIB_TAG_DOIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
Object **ED_undo_editmode_objects_from_view_layer(const Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
uint *r_len)
|
||||
Vector<Object *> ED_undo_editmode_objects_from_view_layer(const Scene *scene,
|
||||
ViewLayer *view_layer)
|
||||
{
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
Base *baseact = BKE_view_layer_active_base_get(view_layer);
|
||||
if ((baseact == nullptr) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
|
||||
return static_cast<Object **>(MEM_mallocN(0, __func__));
|
||||
return {};
|
||||
}
|
||||
const int len = undo_editmode_objects_from_view_layer_prepare(
|
||||
scene, view_layer, baseact->object);
|
||||
Set<const ID *> object_data;
|
||||
const short object_type = baseact->object->type;
|
||||
int i = 0;
|
||||
Object **objects = static_cast<Object **>(MEM_malloc_arrayN(len, sizeof(*objects), __func__));
|
||||
Vector<Object *> objects(object_data.size());
|
||||
/* Base iteration, starting with the active-base to ensure it's the first item in the array.
|
||||
* Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
|
||||
for (Base *base = baseact,
|
||||
@@ -943,33 +912,26 @@ Object **ED_undo_editmode_objects_from_view_layer(const Scene *scene,
|
||||
{
|
||||
Object *ob = base->object;
|
||||
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
|
||||
ID *id = static_cast<ID *>(ob->data);
|
||||
if (id->tag & LIB_TAG_DOIT) {
|
||||
objects[i++] = ob;
|
||||
id->tag &= ~LIB_TAG_DOIT;
|
||||
if (object_data.add(static_cast<const ID *>(ob->data))) {
|
||||
objects.append(ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
BLI_assert(i == len);
|
||||
BLI_assert(object_data.is_empty());
|
||||
BLI_assert(objects[0] == baseact->object);
|
||||
*r_len = len;
|
||||
return objects;
|
||||
}
|
||||
|
||||
Base **ED_undo_editmode_bases_from_view_layer(const Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
uint *r_len)
|
||||
Vector<Base *> ED_undo_editmode_bases_from_view_layer(const Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
Base *baseact = BKE_view_layer_active_base_get(view_layer);
|
||||
if ((baseact == nullptr) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
|
||||
return static_cast<Base **>(MEM_mallocN(0, __func__));
|
||||
return {};
|
||||
}
|
||||
const int len = undo_editmode_objects_from_view_layer_prepare(
|
||||
scene, view_layer, baseact->object);
|
||||
Set<const ID *> object_data;
|
||||
const short object_type = baseact->object->type;
|
||||
int i = 0;
|
||||
Base **base_array = static_cast<Base **>(MEM_malloc_arrayN(len, sizeof(*base_array), __func__));
|
||||
Vector<Base *> bases;
|
||||
/* Base iteration, starting with the active-base to ensure it's the first item in the array.
|
||||
* Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
|
||||
for (Base *base = BKE_view_layer_active_base_get(view_layer),
|
||||
@@ -979,18 +941,15 @@ Base **ED_undo_editmode_bases_from_view_layer(const Scene *scene,
|
||||
{
|
||||
Object *ob = base->object;
|
||||
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
|
||||
ID *id = static_cast<ID *>(ob->data);
|
||||
if (id->tag & LIB_TAG_DOIT) {
|
||||
base_array[i++] = base;
|
||||
id->tag &= ~LIB_TAG_DOIT;
|
||||
if (object_data.add(static_cast<const ID *>(ob->data))) {
|
||||
bases.append(base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(i == len);
|
||||
BLI_assert(base_array[0] == baseact);
|
||||
*r_len = len;
|
||||
return base_array;
|
||||
BLI_assert(object_data.is_empty());
|
||||
BLI_assert(bases[0] == baseact);
|
||||
return bases;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
Reference in New Issue
Block a user