Sculpt: Rewrite BMLog to support customdata and geometry undo steps #113539

Open
Joseph Eagar wants to merge 18 commits from JosephEagar/blender:temp-dyntopo-bmlog into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Member

This PR rewrites BMLog in C++ to support attributes and geometry (full mesh) undo steps.

Developer Notes:

  • The external API is the same
  • BMLogEntry now stores an internal list of changesets; these can be delta change sets or full meshes.
This PR rewrites `BMLog` in C++ to support attributes and geometry (full mesh) undo steps. Developer Notes: * The external API is the same * `BMLogEntry` now stores an internal list of changesets; these can be delta change sets or full meshes.
Joseph Eagar added 1 commit 2023-10-11 13:55:55 +02:00
Joseph Eagar added 1 commit 2023-10-11 14:03:48 +02:00
Joseph Eagar added 1 commit 2023-10-11 14:04:54 +02:00
Joseph Eagar added 1 commit 2023-10-11 14:08:30 +02:00
Joseph Eagar added 1 commit 2023-10-11 20:52:36 +02:00
Joseph Eagar added 1 commit 2023-10-11 21:08:02 +02:00
Hans Goudey requested changes 2023-10-12 11:11:07 +02:00
Hans Goudey left a comment
Member

Thanks a lot for for splitting out this change. This does look mostly self contained like you mentioned. I did a first round of review-- I hope everything is clear. I mostly looked at bmesh_log.cc for now, not so much of bmesh_idmap. I just wanted to highlight two comments that are a bit larger than the others.

  • Temporary layer flags Generally Sergey and I weren't convinced by the need for this abstraction. It definitely adds a fair amount of complexity to the CustomData code, for something that could probably be handled at a higher level. Most uses of it in main are from CD_NORMAL, which has been moving out of CustomData anyway for the past couple years. BMesh is definitely different, but it would be better to have this conversation outside of this PR, in other words remove the handling of CD_FLAG_TEMPORARY here in this PR.
  • BMLogCallbacks This was another non-obvious part of the design we noticed, and it doesn't seem used here. If possible, let's also consider that as a separate step.
Thanks a lot for for splitting out this change. This does look mostly self contained like you mentioned. I did a first round of review-- I hope everything is clear. I mostly looked at `bmesh_log.cc` for now, not so much of `bmesh_idmap`. I just wanted to highlight two comments that are a bit larger than the others. - **Temporary layer flags** Generally Sergey and I weren't convinced by the need for this abstraction. It definitely adds a fair amount of complexity to the CustomData code, for something that could probably be handled at a higher level. Most uses of it in main are from `CD_NORMAL`, which has been moving out of CustomData anyway for the past couple years. BMesh is definitely different, but it would be better to have this conversation outside of this PR, in other words remove the handling of `CD_FLAG_TEMPORARY` here in this PR. - **`BMLogCallbacks`** This was another non-obvious part of the design we noticed, and it doesn't seem used here. If possible, let's also consider that as a separate step.
@ -1120,3 +1120,3 @@
Mesh *mesh = static_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
BM_mesh_bm_to_me(nullptr, bm, mesh, params);
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
if (me_settings) { /* BMLog calls this with me_settings as null. */
Member

This function is really just two lines long. Better to inline it than to tweak it here just for that use case.

This function is really just two lines long. Better to inline it than to tweak it here just for that use case.
JosephEagar marked this conversation as resolved
@ -195,7 +195,6 @@
#include "intern/bmesh_edgeloop.h"
#include "intern/bmesh_interp.h"
#include "intern/bmesh_iterators.h"
#include "intern/bmesh_log.h"
Member

Better to revert this change and consider it more holistically as a next step

Better to revert this change and consider it more holistically as a next step
JosephEagar marked this conversation as resolved
@ -0,0 +1,409 @@
#include "MEM_guardedalloc.h"
Member

Missing copyright here and GPL license here

Missing copyright here and GPL license here
JosephEagar marked this conversation as resolved
@ -0,0 +73,4 @@
void BM_idmap_clear_attributes_mesh(Mesh *me);
/* Elem -> ID. */
template<typename T = BMElem> BLI_INLINE int BM_idmap_get_id(BMIdMap *map, T *elem)
Member

BLI_INLINE -> inline

`BLI_INLINE` -> `inline`
JosephEagar marked this conversation as resolved
@ -27,0 +46,4 @@
using blender::Vector;
/* Avoid C++ runtime type ids. */
enum BMLogSetType { LOG_SET_DIFF, LOG_SET_FULL };
Member

The following disallows implicit conversions and looks a bit nicer later.

enum class BMLogSetType { Diff, Full };
The following disallows implicit conversions and looks a bit nicer later. ``` enum class BMLogSetType { Diff, Full };
JosephEagar marked this conversation as resolved
@ -27,0 +61,4 @@
return false;
}
CustomData test_a = *data_a;
Member

Let's avoid making local copies here and just compare the members we care about explicitly, without memcpy. That seems less hacky to me, and clearer to the reader. If things change in BMesh customdata, this code will probably have to change anyway.

Let's avoid making local copies here and just compare the members we care about explicitly, without `memcpy`. That seems less hacky to me, and clearer to the reader. If things change in BMesh customdata, this code will probably have to change anyway.
JosephEagar marked this conversation as resolved
@ -27,0 +114,4 @@
CustomData_update_typemap(dest);
}
Member

Since it's a swap, there isn't really a "source", I'd suggest calling these data_a, data_b, block_a, and block_b.

Since it's a swap, there isn't really a "source", I'd suggest calling these `data_a`, `data_b`, `block_a`, and `block_b`.
JosephEagar marked this conversation as resolved
@ -27,0 +130,4 @@
CustomData_bmesh_set_default(source, dest_block);
}
void *scratch = alloca(dest->totsize);
Member

In C++ we shouldn't have to use alloca at all-- we have vectors with inline buffers, but even better in this case, DynamicStackBuffer, which should be able to replace this pretty simply.

In C++ we shouldn't have to use `alloca` at all-- we have vectors with inline buffers, but even better in this case, `DynamicStackBuffer`, which should be able to replace this pretty simply.
Author
Member

That's a nice little class.

That's a nice little class.
JosephEagar marked this conversation as resolved
@ -27,0 +159,4 @@
};
template<typename T> struct LogElemAlloc {
BLI_mempool *pool;
Member

I'm not convinced it makes sense to have a type-safe wrapper around BLI_mempool that's local to this file. I would advocate for just using BLI_mempool directly here and saving further C++ conversion for later. Especially avoiding the iterator implementation here would be nice, those are a bit non-trivial.

That said, I understand if you think this is essential to the rest of the patch, and it could also be generalized later if we had too.

I'm not convinced it makes sense to have a type-safe wrapper around `BLI_mempool` that's local to this file. I would advocate for just using `BLI_mempool` directly here and saving further C++ conversion for later. Especially avoiding the iterator implementation here would be nice, those are a bit non-trivial. That said, I understand if you think this is essential to the rest of the patch, and it could also be generalized later if we had too.
Author
Member

The problem is that BMLogFace is a non-trivial type so it's constructor has to be called via in-place new. Maybe I should make a PR for this though.

edit: Of course BMLogFace doesn't need a Vector, so this doesn't apply. I'll just get rid of the wrapper entirely.

The problem is that `BMLogFace` is a non-trivial type so it's constructor has to be called via in-place new. Maybe I should make a PR for this though. edit: Of course BMLogFace doesn't need a Vector, so this doesn't apply. I'll just get rid of the wrapper entirely.
JosephEagar marked this conversation as resolved
@ -27,0 +164,4 @@
class iterator {
LogElemAlloc<T> *alloc;
BLI_mempool_iter iter;
void *elem = nullptr, *first;
Member

Declare variables on separate lines, it's just clearer that way

Declare variables on separate lines, it's just clearer that way
JosephEagar marked this conversation as resolved
@ -27,0 +280,4 @@
};
struct BMLogFace : public BMLogElem<BMFace> {
Vector<int, 3> verts;
Member

Vector has a fair amount of overhead in situations like this. Since the size is known at compile time and the code doesn't use more than that size, std::array would be a better choice.

`Vector` has a fair amount of overhead in situations like this. Since the size is known at compile time and the code doesn't use more than that size, `std::array` would be a better choice.
Author
Member

I'd forgotten that master's PBVH_BMESH forcibly triangulates everything.

I'd forgotten that master's PBVH_BMESH forcibly triangulates everything.
JosephEagar marked this conversation as resolved
@ -27,0 +301,4 @@
struct BMLogSetBase {
BMLogSetType type;
BMLogEntry *entry = nullptr; /* Parent entry */
Member

It would be very nice to avoid this back pointer. Is that possible?

It would be very nice to avoid this back pointer. Is that possible?
Author
Member

I could go with a dependency injection pattern, bundle the API methods I need into a separate struct that forwards back to BMEntry.

I could go with a dependency injection pattern, bundle the API methods I need into a separate struct that forwards back to BMEntry.
@ -27,0 +311,4 @@
{
return "";
}
virtual void undo(BMesh * /*bm*/, BMLogCallbacks * /*callbacks*/) {}
Member

virtual void undo(BMesh * /*bm*/, BMLogCallbacks * /*callbacks*/) = 0;

That's a nice way to force sub-classes to implement the methods and end up with an error otherwise.

`virtual void undo(BMesh * /*bm*/, BMLogCallbacks * /*callbacks*/) = 0;` That's a nice way to force sub-classes to implement the methods and end up with an error otherwise.
JosephEagar marked this conversation as resolved
@ -27,0 +364,4 @@
BMLogSetFullMesh(BMesh *bm, BMLogEntry *entry, BMIdMap *idmap)
: BMLogSetBase(entry, LOG_SET_FULL)
{
printf("Log full mesh\n");
Member

Lost debug print here

Lost debug print here
JosephEagar marked this conversation as resolved
@ -27,0 +371,4 @@
/* Ensure we write idmap attrs. */
set_idlayer_temporary_flag(&bm->vdata, BM_VERT, false);
set_idlayer_temporary_flag(&bm->edata, BM_EDGE, false);
Member

I described this more in the overall comment, but it would be good to avoid the need to involve CD_FLAG_TEMPORARY here. I think it would be better if attributes were deleted or not copied explicitly when leaving sculpt mode. This CD_FLAG_TEMPORARY stuff (currently mostly used for the CD_NORMAL which is a not-great design anyway) complicates things and is clearly a leaky abstraction.

Either way, I'd like to leave the complexity for later or not involve it here in the logging.

I described this more in the overall comment, but it would be good to avoid the need to involve `CD_FLAG_TEMPORARY` here. I think it would be better if attributes were deleted or not copied explicitly when leaving sculpt mode. This `CD_FLAG_TEMPORARY` stuff (currently mostly used for the `CD_NORMAL` which is a not-great design anyway) complicates things and is clearly a leaky abstraction. Either way, I'd like to leave the complexity for later or not involve it here in the logging.
Author
Member

I'll get rid of it then and just have it delete the idmap layers on sculpt mode exit.

I'll get rid of it then and just have it delete the idmap layers on sculpt mode exit.
Author
Member

I'll get rid of it then and just have it delete the idmap layers on sculpt mode exit.

I'll get rid of it then and just have it delete the idmap layers on sculpt mode exit.
JosephEagar marked this conversation as resolved
@ -27,0 +400,4 @@
void swap(BMesh *bm)
{
CustomData_MeshMasks cd_mask_extra = {0, 0, 0, 0, 0};
Member

Can be a bit simpler in C++:

CustomData_MeshMasks cd_mask_extra{};

Can be a bit simpler in C++: `CustomData_MeshMasks cd_mask_extra{};`
JosephEagar marked this conversation as resolved
@ -27,0 +419,4 @@
BMeshFromMeshParams params2 = {};
params2.cd_mask_extra = cd_mask_extra;
params2.calc_face_normal = params2.add_key_index = params2.use_shapekey = false;
Member

Setting these to false is already done by = {} above

Setting these to false is already done by `= {}` above
JosephEagar marked this conversation as resolved
@ -27,0 +435,4 @@
bm->shapenr = shapenr;
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
Member

Setting the indices and tables dirty seems like something BM_mesh_bm_from_me should be doing. If so, maybe we can split that out and commit it to main. It seems like it would be a problem to fill the BMesh with new data and not reset the tables

Setting the indices and tables dirty seems like something `BM_mesh_bm_from_me` should be doing. If so, maybe we can split that out and commit it to main. It seems like it would be a problem to fill the BMesh with new data and not reset the tables
Author
Member

I'm actually not sure this is needed at all, you might be right. I'll try removing it.

I'm actually not sure this is needed at all, you might be right. I'll try removing it.
@ -27,0 +464,4 @@
}
}
Mesh *mesh = nullptr;
Member

The style guide mentions declaring class variables above all class methods

The style guide mentions declaring class variables above all class methods
JosephEagar marked this conversation as resolved
@ -27,0 +494,4 @@
return "loop";
case BM_FACE:
return "face";
default:
Member

The default case can be moved out of the switch and a BLI_assert_unreachable() can be added

The default case can be moved out of the switch and a `BLI_assert_unreachable()` can be added
JosephEagar marked this conversation as resolved
@ -27,0 +518,4 @@
struct BMLogEntry {
BMLogEntry *next = nullptr, *prev = nullptr;
Vector<BMLogSetBase *> sets;
Member

Vector<std::unique_ptr<BMLogSetBase>>

Since BMLogSetBase has a virtual destructor, this should work fine :)

`Vector<std::unique_ptr<BMLogSetBase>>` Since `BMLogSetBase` has a virtual destructor, this should work fine :)
JosephEagar marked this conversation as resolved
@ -27,0 +581,4 @@
return nullptr;
}
void copy_custom_data(CustomData *source, CustomData *dest, void *src_block, void **dest_block)
Member

Make the source variables const

Make the source variables const
JosephEagar marked this conversation as resolved
@ -27,0 +638,4 @@
CustomData_free(&pdata, 0);
}
void print()
Member

Can we remove this print function for now, to avoid having the conversation about all these variable names and temporary code?

Can we remove this print function for now, to avoid having the conversation about all these variable names and temporary code?
Author
Member

The print function is called by sculpt_undo's debug printing.

The print function is called by sculpt_undo's debug printing.
JosephEagar marked this conversation as resolved
@ -47,3 +71,2 @@
int BM_log_length(const BMLog *log);
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry, bool for_redo);
/** Apply a consistent ordering to BMesh vertices and faces. */
Member

A lot of the changes to comments in this file look unnecessary. I do think that some of the previous comments were a bit too verbose or exposed internal details, but I think it would be much nicer to change them later, to make what's actually changing in this PR clearer.

So it would be great if you could edit the diff here to only keep the necessary changes.

A lot of the changes to comments in this file look unnecessary. I do think that some of the previous comments were a bit too verbose or exposed internal details, but I think it would be much nicer to change them later, to make what's actually changing in this PR clearer. So it would be great if you could edit the diff here to only keep the necessary changes.
JosephEagar marked this conversation as resolved
@ -15,3 +47,2 @@
typedef struct BMLog BMLog;
typedef struct BMLogEntry BMLogEntry;
struct BMLogCallbacks {
Member

It looks to me like the BMLogCallbacks aren't used. If that's so, I'd really prefer to not include them for now, to make this change more minimal and clearer.

It looks to me like the `BMLogCallbacks` aren't used. If that's so, I'd really prefer to not include them for now, to make this change more minimal and clearer.
JosephEagar marked this conversation as resolved
Author
Member

Thanks a lot for for splitting out this change. This does look mostly self contained like you mentioned. I did a first round of review-- I hope everything is clear. I mostly looked at bmesh_log.cc for now, not so much of bmesh_idmap. I just wanted to highlight two comments that are a bit larger than the others.

  • Temporary layer flags Generally Sergey and I weren't convinced by the need for this abstraction. It definitely adds a fair amount of complexity to the CustomData code, for something that could probably be handled at a higher level. Most uses of it in main are from CD_NORMAL, which has been moving out of CustomData anyway for the past couple years. BMesh is definitely different, but it would be better to have this conversation outside of this PR, in other words remove the handling of CD_FLAG_TEMPORARY here in this PR.

Which uses of CD_FLAG_TEMPORARY? Do you mean the idmap attributes?

  • BMLogCallbacks This was another non-obvious part of the design we noticed, and it doesn't seem used here. If possible, let's also consider that as a separate step.

That's for incrementally updating the PBVH. Since that's going to be a different PR it can be removed, yes.

> Thanks a lot for for splitting out this change. This does look mostly self contained like you mentioned. I did a first round of review-- I hope everything is clear. I mostly looked at `bmesh_log.cc` for now, not so much of `bmesh_idmap`. I just wanted to highlight two comments that are a bit larger than the others. > > - **Temporary layer flags** Generally Sergey and I weren't convinced by the need for this abstraction. It definitely adds a fair amount of complexity to the CustomData code, for something that could probably be handled at a higher level. Most uses of it in main are from `CD_NORMAL`, which has been moving out of CustomData anyway for the past couple years. BMesh is definitely different, but it would be better to have this conversation outside of this PR, in other words remove the handling of `CD_FLAG_TEMPORARY` here in this PR. Which uses of CD_FLAG_TEMPORARY? Do you mean the idmap attributes? > - **`BMLogCallbacks`** This was another non-obvious part of the design we noticed, and it doesn't seem used here. If possible, let's also consider that as a separate step. That's for incrementally updating the PBVH. Since that's going to be a different PR it can be removed, yes.
Member

Which uses of CD_FLAG_TEMPORARY? Do you mean the idmap attributes?

Okay, yeah that's the part I didn't look into in depth in this PR. But yes, I do mean those. Just to be clear, the main intention of using CD_FLAG_TEMPORARY is to avoid having these idmap attributes when exiting dynamic topology, right?

>Which uses of CD_FLAG_TEMPORARY? Do you mean the idmap attributes? Okay, yeah that's the part I didn't look into in depth in this PR. But yes, I do mean those. Just to be clear, the main intention of using `CD_FLAG_TEMPORARY` is to avoid having these idmap attributes when exiting dynamic topology, right?
Joseph Eagar added 1 commit 2023-10-12 19:45:53 +02:00
89c750d9ec * Remove BMLogCallbacks.
* Inline the two lines from BKE_mesh_from_bmesh_nomain we need.
* IDMap no longer flags its attributes as temporary.
  They're now explicitly deleted when the BMLog is.
Joseph Eagar added 1 commit 2023-10-12 19:46:56 +02:00
Joseph Eagar added 1 commit 2023-10-12 19:48:24 +02:00
Joseph Eagar added 1 commit 2023-10-12 19:58:39 +02:00
Joseph Eagar added 1 commit 2023-10-12 20:33:30 +02:00
Joseph Eagar added 1 commit 2023-10-12 20:34:23 +02:00
Joseph Eagar added 1 commit 2023-10-12 21:04:00 +02:00
e20054b1e6 * Fix crash
* Removed unneeded copy_custom_data method
* Rename variables
* Use DynamicStackBuffer
Author
Member

Which uses of CD_FLAG_TEMPORARY? Do you mean the idmap attributes?

Okay, yeah that's the part I didn't look into in depth in this PR. But yes, I do mean those. Just to be clear, the main intention of using CD_FLAG_TEMPORARY is to avoid having these idmap attributes when exiting dynamic topology, right?

Right. I went ahead and removed CD_FLAG_TEMPORARY and just explicitly deleted them.

> >Which uses of CD_FLAG_TEMPORARY? Do you mean the idmap attributes? > > Okay, yeah that's the part I didn't look into in depth in this PR. But yes, I do mean those. Just to be clear, the main intention of using `CD_FLAG_TEMPORARY` is to avoid having these idmap attributes when exiting dynamic topology, right? Right. I went ahead and removed `CD_FLAG_TEMPORARY` and just explicitly deleted them.
Joseph Eagar added 1 commit 2023-10-13 20:11:16 +02:00
Joseph Eagar added 1 commit 2023-10-17 19:22:30 +02:00
Joseph Eagar added 2 commits 2023-10-24 04:07:52 +02:00
cec4f14fbe Merge branch 'main' into temp-dyntopo-bmlog
Also removed BMLogEntry.print and did a
few other cleanups.
dff2eb8cbf Restore various comments and method orderings.
Note that the comment for BM_log_free is left out,
I don't think it was ever correct.
Joseph Eagar added 1 commit 2023-10-24 04:14:17 +02:00
Hans Goudey reviewed 2023-11-02 13:39:56 +01:00
Hans Goudey left a comment
Member

One big picture question-- could you motivate the need for the change to the ID map in the description? It looks like this replaces this:

  RangeTreeUInt *unused_ids;
  GHash *id_to_elem;
  GHash *elem_to_id;

But the need to store an integer per element is not great-- seems that it will significantly increase the memory usage-- especially for edges and face corners. Maybe I'm missing something?

One big picture question-- could you motivate the need for the change to the ID map in the description? It looks like this replaces this: ``` RangeTreeUInt *unused_ids; GHash *id_to_elem; GHash *elem_to_id; ``` But the need to store an integer per element is not great-- seems that it will significantly increase the memory usage-- especially for edges and face corners. Maybe I'm missing something?
@ -0,0 +1,2 @@
#include "intern/bmesh_log.h"
Member

This file should be removed for now. We can change to more granular bmesh includes as a separate step later.

This file should be removed for now. We can change to more granular bmesh includes as a separate step later.
@ -21,0 +56,4 @@
/* `customdata_layout_is_same` and `customdata_copy_all_layout` are
* used internally by BMLog and probably don't have much use elsewhere.
* They ignore all copy-on-write semantics which makes sense since this
Member

Implicit sharing shouldn't make a difference in the BMesh case anyway, since data is always null. So it should be fine to just use the general API functions.

Implicit sharing shouldn't make a difference in the BMesh case anyway, since `data` is always null. So it should be fine to just use the general API functions.
@ -21,0 +68,4 @@
}
for (int i : IndexRange(data_a->totlayer)) {
CustomDataLayer &layer_a = data_a->layers[i];
Member

const CustomDataLayer

`const CustomDataLayer`
@ -21,0 +84,4 @@
/* Copies all customdata layers without allocating data
* and without respect to type masks or NO_COPY/etc flags.
*/
static void customdata_copy_all_layout(const CustomData *source, CustomData *dest)
Member

This seems unnecessary logically now, CustomData_copy_layout should do the trick, and would be consistent with how CustomData_bmesh_copy_data is used later too

This seems unnecessary logically now, `CustomData_copy_layout` should do the trick, and would be consistent with how `CustomData_bmesh_copy_data` is used later too
@ -21,0 +302,4 @@
#if 0
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
Member

I thought we agreed regenerating the indices and tables was unnecessary here, and should already be dealt with by BM_mesh_bm_from_me or elsewhere.

I thought we agreed regenerating the indices and tables was unnecessary here, and should already be dealt with by `BM_mesh_bm_from_me` or elsewhere.
Author
Member

Not sure what I was thinking. It's funny I #if 0'd it out.

Not sure what I was thinking. It's funny I `#if 0'`d it out.
@ -103,1 +118,4 @@
/* Now log full mesh again after triangulation. */
if (for_undo && ss->bm->totface != faces_num) {
BM_log_full_mesh(ss->bm, ss->bm_log);
Member

Why do we need to log the mesh before and after triangulation? It seems like just after triangulation would be enough, since the before state would be captured by the undo step before that.

Why do we need to log the mesh before and after triangulation? It seems like just after triangulation would be enough, since the before state would be captured by the undo step before that.
Author
Member

I'll have to look into it. You do need two pushes per step (this is how geometry undo steps work too) but the first may've already happened at this point.

I'll have to look into it. You do need two pushes per step (this is how geometry undo steps work too) but the first may've already happened at this point.
Author
Member

One big picture question-- could you motivate the need for the change to the ID map in the description? It looks like this replaces this:

  RangeTreeUInt *unused_ids;
  GHash *id_to_elem;
  GHash *elem_to_id;

But the need to store an integer per element is not great-- seems that it will significantly increase the memory usage-- especially for edges and face corners. Maybe I'm missing something?

It uses less memory then storing the same amount of data in two hash maps and a range tree. :) Face corners don't get IDs btw, they don't need them (they're logged with their owning faces).

> One big picture question-- could you motivate the need for the change to the ID map in the description? It looks like this replaces this: > ``` > RangeTreeUInt *unused_ids; > GHash *id_to_elem; > GHash *elem_to_id; > ``` > But the need to store an integer per element is not great-- seems that it will significantly increase the memory usage-- especially for edges and face corners. Maybe I'm missing something? It uses less memory then storing the same amount of data in two hash maps and a range tree. :) Face corners don't get IDs btw, they don't need them (they're logged with their owning faces).
Author
Member

I did a lot of profiling on the performance of RangeTree, it was a significant source of performance loss. What I ended up doing was replacing it with a simple free list. If you need to remove an arbitrary ID from the freelist it does a simple linear search, unless the free list grows beyond a certain size in which case the code maintains an id-to-freelist-index hashmap.

I did a lot of profiling on the performance of RangeTree, it was a significant source of performance loss. What I ended up doing was replacing it with a simple free list. If you need to remove an arbitrary ID from the freelist it does a simple linear search, unless the free list grows beyond a certain size in which case the code maintains an id-to-freelist-index hashmap.
Member

Thanks for the info, that makes sense! My remaining comment about the idmap is probably the attribute names then. Ideally they wouldn't be specific to sculpt with .sculpt at the beginning.

I wonder how the semantics compare to the id vertex attribute used in geometry nodes. If they were the same (or similar enough), they could be id and id_edge and id_face.

Thanks for the info, that makes sense! My remaining comment about the idmap is probably the attribute names then. Ideally they wouldn't be specific to sculpt with `.sculpt` at the beginning. I wonder how the semantics compare to the `id` vertex attribute used in geometry nodes. If they were the same (or similar enough), they could be `id` and `id_edge` and `id_face`.
This pull request has changes conflicting with the target branch.
  • source/blender/blenkernel/BKE_paint.hh
  • source/blender/blenkernel/intern/paint.cc
  • source/blender/blenkernel/intern/pbvh_bmesh.cc
  • source/blender/bmesh/CMakeLists.txt
  • source/blender/bmesh/intern/bmesh_log.cc
  • source/blender/bmesh/intern/bmesh_log.h
  • source/blender/editors/sculpt_paint/sculpt.cc
  • source/blender/editors/sculpt_paint/sculpt_dyntopo.cc
  • source/blender/editors/sculpt_paint/sculpt_intern.hh
  • source/blender/editors/sculpt_paint/sculpt_ops.cc

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u temp-dyntopo-bmlog:JosephEagar-temp-dyntopo-bmlog
git checkout JosephEagar-temp-dyntopo-bmlog
Sign in to join this conversation.
No reviewers
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#113539
No description provided.