Blender V5.0
editmesh_undo.cc File Reference
#include <algorithm>
#include <variant>
#include "MEM_guardedalloc.h"
#include "CLG_log.h"
#include "DNA_key_types.h"
#include "DNA_layer_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_array_utils.h"
#include "BLI_implicit_sharing.hh"
#include "BLI_listbase.h"
#include "BLI_math_base.h"
#include "BLI_string.h"
#include "BLI_task.hh"
#include "BLI_vector.hh"
#include "BKE_context.hh"
#include "BKE_customdata.hh"
#include "BKE_deform.hh"
#include "BKE_editmesh.hh"
#include "BKE_key.hh"
#include "BKE_layer.hh"
#include "BKE_lib_id.hh"
#include "BKE_main.hh"
#include "BKE_mesh.hh"
#include "BKE_object.hh"
#include "BKE_undo_system.hh"
#include "DEG_depsgraph.hh"
#include "ED_mesh.hh"
#include "ED_object.hh"
#include "ED_undo.hh"
#include "ED_util.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#include "BLI_array_store.h"
#include "BLI_array_store_utils.h"
#include "BLI_task.h"

Go to the source code of this file.

Classes

struct  BArrayCustomData
struct  UndoMesh
struct  UMArrayData
struct  MeshUndoStep_Elem
struct  MeshUndoStep_SceneData
struct  MeshUndoStep

Macros

#define USE_ARRAY_STORE
#define ARRAY_CHUNK_SIZE_IN_BYTES   65536
#define ARRAY_CHUNK_NUM_MIN   256
#define USE_ARRAY_STORE_THREAD
#define USE_ARRAY_STORE_RLE

Functions

static void * undomesh_from_editmesh (UndoMesh *um, BMEditMesh *em, Key *key, const ListBase *vertex_group_names, const int vertex_group_active_index, UndoMesh *um_ref)
static void undomesh_to_editmesh (UndoMesh *um, BMEditMesh *em, ListBase *vertex_group_names, int *vertex_group_active_index)
static void undomesh_free_data (UndoMesh *um)
static Objecteditmesh_object_from_context (bContext *C)
Undo Conversion
static size_t array_chunk_size_calc (const size_t stride)
static bool um_customdata_layer_use_rle (const BArrayCustomData *bcd)
Array Store Utilities
static UndoMesh ** mesh_undostep_reference_elems_from_objects (Object **object, int object_len)
Implements ED Undo System
Note
This is similar for all edit-mode types.
static bool mesh_undosys_poll (bContext *C)
static bool mesh_undosys_step_encode (bContext *C, Main *bmain, UndoStep *us_p)
static void mesh_undosys_step_decode (bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir, bool)
static void mesh_undosys_step_free (UndoStep *us_p)
static void mesh_undosys_foreach_ID_ref (UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
void ED_mesh_undosys_type (UndoType *ut)

Variables

static CLG_LogRef LOG = {"undo.mesh"}

Array Store

#define ARRAY_STORE_INDEX_NUM   (ARRAY_STORE_INDEX_MSEL + 1)
enum  {
  ARRAY_STORE_INDEX_VERT = 0 , ARRAY_STORE_INDEX_EDGE , ARRAY_STORE_INDEX_LOOP , ARRAY_STORE_INDEX_POLY ,
  ARRAY_STORE_INDEX_POLY_OFFSETS , ARRAY_STORE_INDEX_SHAPE , ARRAY_STORE_INDEX_MSEL
}
struct { 
   BArrayStore_AtSize   bs_stride [ARRAY_STORE_INDEX_NUM
   int   users 
   ListBase   local_links 
   TaskPool *   task_pool 
um_arraystore = {{{nullptr}}}
static void um_arraystore_cd_compact (CustomData *cdata, const size_t data_len, const bool create, const int bs_index, const BArrayCustomData *bcd_reference, BArrayCustomData **r_bcd_first)
static void um_arraystore_cd_expand (const BArrayCustomData *bcd, CustomData *cdata, const size_t data_len)
static void um_arraystore_cd_free (BArrayCustomData *bcd, const int bs_index)
static void um_arraystore_compact_ex (UndoMesh *um, const UndoMesh *um_ref, bool create)
static void um_arraystore_compact (UndoMesh *um, const UndoMesh *um_ref)
static void um_arraystore_compact_with_info (UndoMesh *um, const UndoMesh *um_ref)
static void um_arraystore_compact_cb (TaskPool *__restrict, void *taskdata)
static void um_arraystore_expand_clear (UndoMesh *um)
static void um_arraystore_expand (UndoMesh *um)
static void um_arraystore_free (UndoMesh *um)

Macro Definition Documentation

◆ ARRAY_CHUNK_NUM_MIN

#define ARRAY_CHUNK_NUM_MIN   256

Definition at line 72 of file editmesh_undo.cc.

Referenced by array_chunk_size_calc().

◆ ARRAY_CHUNK_SIZE_IN_BYTES

#define ARRAY_CHUNK_SIZE_IN_BYTES   65536

This used to be much smaller (256), but this caused too much overhead when selection moved to boolean arrays. Especially with high-poly meshes where managing a large number of small chunks could be slow, blocking user interactivity. Use a larger value (in bytes) which calculates the chunk size using array_chunk_size_calc. See: #105046 & #105205.

Definition at line 71 of file editmesh_undo.cc.

Referenced by array_chunk_size_calc().

◆ ARRAY_STORE_INDEX_NUM

#define ARRAY_STORE_INDEX_NUM   (ARRAY_STORE_INDEX_MSEL + 1)

Definition at line 199 of file editmesh_undo.cc.

Referenced by um_arraystore_compact_with_info(), and um_arraystore_free().

◆ USE_ARRAY_STORE

#define USE_ARRAY_STORE

Definition at line 53 of file editmesh_undo.cc.

◆ USE_ARRAY_STORE_RLE

#define USE_ARRAY_STORE_RLE

Use run length encoding for boolean custom-data.

Avoid poor performance caused by boolean arrays not having enough uniqueness to efficiently de-duplicate, see: #136737.

NOTE(@ideasman42): This has the down-side that creating undo steps needs to encode data before comparing it with the previous state (when creating each undo step). Adding additional work even when nothing change.

Since there is overhead for RLE encoding this is only used on boolean array, typically used for storing selection/hidden state as well as edge flags. The encoding has also been optimized for performance instead of "compression" which would pack bits into the smallest possible space.

In practice, arrays of 32 million booleans (on an AMD TRX 3990X):

  • ~0.11 seconds for random data.
  • ~0.0025 seconds uniform arrays. ... so the tradeoff seems reasonable.

There is also the benefit of reduced memory use, although that isn't the goal.

Definition at line 98 of file editmesh_undo.cc.

◆ USE_ARRAY_STORE_THREAD

#define USE_ARRAY_STORE_THREAD

Definition at line 74 of file editmesh_undo.cc.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Store separate BArrayStore_AtSize so multiple threads can access array stores without locking.

Enumerator
ARRAY_STORE_INDEX_VERT 
ARRAY_STORE_INDEX_EDGE 
ARRAY_STORE_INDEX_LOOP 
ARRAY_STORE_INDEX_POLY 
ARRAY_STORE_INDEX_POLY_OFFSETS 
ARRAY_STORE_INDEX_SHAPE 
ARRAY_STORE_INDEX_MSEL 

Definition at line 190 of file editmesh_undo.cc.

Function Documentation

◆ array_chunk_size_calc()

size_t array_chunk_size_calc ( const size_t stride)
static

◆ ED_mesh_undosys_type()

◆ editmesh_object_from_context()

◆ mesh_undostep_reference_elems_from_objects()

UndoMesh ** mesh_undostep_reference_elems_from_objects ( Object ** object,
int object_len )
static

Create an array of UndoMesh from objects.

where each element in the resulting array is the most recently created undo-mesh for the object's mesh. When no undo-mesh can be found that array index is nullptr.

This is used for de-duplicating memory between undo steps, failure to find the undo step will store a full duplicate in memory. define DEBUG_PRINT to check memory is de-duplicating as expected.

Definition at line 780 of file editmesh_undo.cc.

References BLI_assert, BLI_ghash_free(), BLI_ghash_insert(), BLI_ghash_len(), BLI_ghash_popkey(), BLI_ghash_ptr_new_ex(), i, Mesh::id, UndoMesh::local_prev, MEM_calloc_arrayN(), MEM_freeN(), UndoMesh::mesh, POINTER_FROM_INT, ID::session_uid, and um_arraystore.

Referenced by mesh_undosys_step_encode().

◆ mesh_undosys_foreach_ID_ref()

void mesh_undosys_foreach_ID_ref ( UndoStep * us_p,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
void * user_data )
static

◆ mesh_undosys_poll()

bool mesh_undosys_poll ( bContext * C)
static

Definition at line 1064 of file editmesh_undo.cc.

References C, and editmesh_object_from_context().

Referenced by ED_mesh_undosys_type(), and mesh_undosys_step_decode().

◆ mesh_undosys_step_decode()

◆ mesh_undosys_step_encode()

◆ mesh_undosys_step_free()

void mesh_undosys_step_free ( UndoStep * us_p)
static

◆ um_arraystore_cd_compact()

◆ um_arraystore_cd_expand()

◆ um_arraystore_cd_free()

◆ um_arraystore_compact()

void um_arraystore_compact ( UndoMesh * um,
const UndoMesh * um_ref )
static

Move data from allocated arrays to de-duplicated states and clear arrays.

Definition at line 584 of file editmesh_undo.cc.

References um_arraystore_compact_ex().

Referenced by um_arraystore_compact_with_info().

◆ um_arraystore_compact_cb()

void um_arraystore_compact_cb ( TaskPool * __restrict,
void * taskdata )
static

◆ um_arraystore_compact_ex()

void um_arraystore_compact_ex ( UndoMesh * um,
const UndoMesh * um_ref,
bool create )
static
Parameters
createWhen false, only free the arrays. This is done since when reading from an undo state, they must be temporarily expanded. then discarded afterwards, having this argument avoids having 2x code paths.

Definition at line 460 of file editmesh_undo.cc.

References Mesh::corners_num, Mesh::edges_num, Mesh::faces_num, UndoMesh::mesh, blender::threading::parallel_invoke(), and Mesh::verts_num.

Referenced by um_arraystore_compact(), and um_arraystore_expand_clear().

◆ um_arraystore_compact_with_info()

void um_arraystore_compact_with_info ( UndoMesh * um,
const UndoMesh * um_ref )
static

◆ um_arraystore_expand()

◆ um_arraystore_expand_clear()

void um_arraystore_expand_clear ( UndoMesh * um)
static

Remove data we only expanded for temporary use.

Definition at line 659 of file editmesh_undo.cc.

References um_arraystore_compact_ex().

Referenced by undomesh_to_editmesh().

◆ um_arraystore_free()

◆ um_customdata_layer_use_rle()

bool um_customdata_layer_use_rle ( const BArrayCustomData * bcd)
static

◆ undomesh_free_data()

◆ undomesh_from_editmesh()

◆ undomesh_to_editmesh()

void undomesh_to_editmesh ( UndoMesh * um,
BMEditMesh * em,
ListBase * vertex_group_names,
int * vertex_group_active_index )
static

Copy data from um into em.

Note
while em defines the "edit-mesh" there are some exceptions which are intentionally kept as separate arguments instead of passing in the Object or Mesh data blocks. This is done to avoid confusion from passing in multiple meshes, where it's not always clear what the source of truth is for mesh data - which can make the logic difficult to reason about.

Definition at line 923 of file editmesh_undo.cc.

References BMeshFromMeshParams::active_shapekey, BKE_defgroup_copy_list(), BKE_editmesh_create(), BKE_editmesh_looptris_and_normals_calc(), BLI_freelistN(), BLI_task_pool_work_and_wait(), bm, BMEditMesh::bm, BM_mesh_bm_from_me(), BM_mesh_create(), BM_SPACEARR_DIRTY_ALL, BMALLOC_TEMPLATE_FROM_ME, BMeshFromMeshParams::calc_face_normal, BMeshFromMeshParams::calc_vert_normal, EDBM_mesh_free_data(), UndoMesh::mesh, BMEditMesh::selectmode, UndoMesh::selectmode, BMesh::shapenr, UndoMesh::shapenr, TIMEIT_END, TIMEIT_START, um_arraystore, um_arraystore_expand(), um_arraystore_expand_clear(), BMeshCreateParams::use_toolflags, Mesh::vertex_group_active_index, and Mesh::vertex_group_names.

Referenced by mesh_undosys_step_decode().

Variable Documentation

◆ bs_stride

Definition at line 202 of file editmesh_undo.cc.

◆ local_links

ListBase local_links

A list of UndoMesh items ordered from oldest to newest used to access previous undo data for a mesh.

Definition at line 209 of file editmesh_undo.cc.

◆ LOG

CLG_LogRef LOG = {"undo.mesh"}
static

We only need this locally.

Definition at line 106 of file editmesh_undo.cc.

◆ task_pool

◆ [struct]

◆ users

int users

Definition at line 203 of file editmesh_undo.cc.