Page MenuHome

Mesh: Move loose edge flag to a separate cache
ClosedPublic

Authored by Hans Goudey (HooglyBoogly) on Nov 14 2022, 11:51 PM.

Details

Summary

As part of T95966, this patch moves loose edge information out of the
flag on each edge and into a new lazily calculated cache in mesh
runtime data. The number of loose edges is also cached, so further
processing can be skipped completely when there are no loose edges.

Previously the ME_LOOSEEDGE flag was updated on a "best effort"
basis. In order to be sure that it was correct, you had to be sure
to call BKE_mesh_calc_edges_loose first. Now the loose edge tag
is always correct. It also doesn't have to be calculated eagerly
in various places like the screw modifier where the complexity
wasn't worth the theoretical performance benefit.

There is also an API function to eagerly set the number of loose
edges to zero to avoid building the cache. This is used by various
primitive nodes, mainly with the goal of improving drawing performance.
This results in a few ms shaved off extracting draw data for some
large meshes in my tests.

In the Python API, MeshEdge.is_loose is no longer an editable
property. No built-in addons set its value anyway. The upside is that
addons can be sure the data is correct based on the mesh when they
retrieve it.

After this, there are only three more flags to move before we can save
1/3 of the memory usage for edges in most meshes.

Note: This patch has similarities with D16530. Some cleanup can be done if that is committed first.

Tests
There is one test failure in the Python OBJ exporter: export_obj_cube.
However, that happens because of incorrect versioning. Opening the
file, all the edges are set to "loose". This patch fixes that issue.

Diff Detail

Repository
rB Blender

Event Timeline

Hans Goudey (HooglyBoogly) requested review of this revision.Nov 14 2022, 11:51 PM
Hans Goudey (HooglyBoogly) created this revision.
Jacques Lucke (JacquesLucke) requested changes to this revision.Nov 15 2022, 12:00 PM

The export_obj_cube test seems to fail for me.

https://builder.blender.org/admin/#/builders/136/builds/227

source/blender/blenkernel/BKE_mesh_types.h
71

less or equal to zero

source/blender/blenkernel/intern/mesh_runtime.cc
70

Looks like this might decrement the same edge multiple times.

This revision now requires changes to proceed.Nov 15 2022, 12:00 PM
Hans Goudey (HooglyBoogly) marked 2 inline comments as done.
Hans Goudey (HooglyBoogly) edited the summary of this revision. (Show Details)
  • Improve comment
  • Fix decrementing count for edge multiple times
source/blender/blenkernel/BKE_mesh_types.h
70

Maybe is_loose_bits?

source/blender/blenkernel/intern/mesh_runtime.cc
60

Will be interesting to optimize this later.

64

Might be more efficient to resize to 0 and then use ->resize(this->totedge, true).

That's because right now the new bits are all first initialized to zero and then again to one.

81

Should probably tag dirty first to make sure that the cache is actually updated.

source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
748

Could probably tag all edges as loose here similar to how we tag none as loose in some places.

Hans Goudey (HooglyBoogly) marked 2 inline comments as done.Nov 16 2022, 10:51 PM
Hans Goudey (HooglyBoogly) added inline comments.
source/blender/blenkernel/intern/mesh_runtime.cc
60

Do you have any ideas? I'm sure there are some possibilities, I don't know much about dealing with bitmaps though. It should be easier after T102359 too.

64

Good idea, thanks.

81

I think I'd like to separate "un-sharing" the cache from setting its value explicitly. That's more aligned to how normals are handled, and it's possible that you'd end up calculating the value explicitly without change the mesh. In that case you'd still want to benefit from the sharing.

source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
748

It could be done, but only at the cost of creating the whole bitmap. Unless I'm actually observing an improvement, I'd like to avoid doing it that eagerly right now.

OTOH, in the future I could see there being three states in the loose edge cache:

  1. count=0, bitmap size=0
  2. count=N, bitmap size=mesh.totedge
  3. count=mesh.totedge, bitmap size=0

For now I'd like to avoid the complexity though.

Hans Goudey (HooglyBoogly) marked an inline comment as done.
Hans Goudey (HooglyBoogly) edited the summary of this revision. (Show Details)
  • Use shared cache
  • Update BitVector name
  • Optimize resizing
  • Mention tagging dirty in comment
Jacques Lucke (JacquesLucke) added inline comments.
source/blender/blenkernel/intern/mesh_runtime.cc
60

Ideas yes, not sure yet if they will actually make it faster though, that makes it interesting. For example:

  • Each thread gets its own bitmap and they are combined in the end.
  • First store a byte per edge to allow multi-threaded writing, and then convert it into a bitmap afterwards.
  • Use atomic compare-exchange to write to the bitmap from multiple threads.
81

Not sure I fully understand. Can you provide a concrete example? To me it seems like this is likely only called when you just changed the mesh, which also means that it is not shared yet.
If you still want to keep tagging dirty separate, there should be a comment explaining why.

This revision is now accepted and ready to land.Nov 17 2022, 12:31 PM