BLI_array_store still performed poorly for boolean arrays or any arrays
where many memory chunks had identical contents since the temporary hash
had many collisions, making lookups slow.
Resolve by ensuring duplicate chunks aren't added to the hash table.
Also increase the memory chunk size for edit-mesh undo to 64kb
which performs well with high poly meshes as it reduces the overhead of
having to manage many small memory chunks.
Notes:
- Before this change performance was quite bad (10-20x worse than v3.3).
- Performance from the test in #105046 is roughly the same as before.
- Performance of #105205 compared with v3.3 is close, even faster at
times but varies much more (likely caused by threading).
As part of #105779, the active status of UV maps won't be stored in
CustomData anymore, so it has to be retrieved from a higher level.
The best way to do that is to retrieve it once and pass around the BMesh
custom data offset as a "key" to the data. This should also decrease
function call overhead in this code (not that it was a bottleneck).
Pull Request: blender/blender#105904
Implements #102359.
Split the `MLoop` struct into two separate integer arrays called
`corner_verts` and `corner_edges`, referring to the vertex each corner
is attached to and the next edge around the face at each corner. These
arrays can be sliced to give access to the edges or vertices in a face.
Then they are often referred to as "poly_verts" or "poly_edges".
The main benefits are halving the necessary memory bandwidth when only
one array is used and simplifications from using regular integer indices
instead of a special-purpose struct.
The commit also starts a renaming from "loop" to "corner" in mesh code.
Like the other mesh struct of array refactors, forward compatibility is
kept by writing files with the older format. This will be done until 4.0
to ease the transition process.
Looking at a small portion of the patch should give a good impression
for the rest of the changes. I tried to make the changes as small as
possible so it's easy to tell the correctness from the diff. Though I
found Blender developers have been very inventive over the last decade
when finding different ways to loop over the corners in a face.
For performance, nearly every piece of code that deals with `Mesh` is
slightly impacted. Any algorithm that is memory bottle-necked should
see an improvement. For example, here is a comparison of interpolating
a vertex float attribute to face corners (Ryzen 3700x):
**Before** (Average: 3.7 ms, Min: 3.4 ms)
```
threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) {
for (const int64_t i : range) {
dst[i] = src[loops[i].v];
}
});
```
**After** (Average: 2.9 ms, Min: 2.6 ms)
```
array_utils::gather(src, corner_verts, dst);
```
That's an improvement of 28% to the average timings, and it's also a
simplification, since an index-based routine can be used instead.
For more examples using the new arrays, see the design task.
Pull Request: blender/blender#104424
A renaming of UI scale factors from names that imply a relationship to
monitor DPI to names that imply that they simply change "scale"
Pull Request: blender/blender#105750
Since normals are derived data, it's always a change to something
else that will cause them to change, like the winding order of a face
or vertex positions. So it's clearer to use tags for those things
directly. It's correct to remove the tag in one place since dirty is
the default state of a new mesh.
The operator went through quite a bit of trouble to pass a color
attribute index to the operator, but then it always used the offset
from the first layer of the active color attribute's type.
Also remove the "copy domains temp" API function, which
generalized this more than necessary, and exposed the internals
of the custom data system a bit more than we would like.
The two removed BKE functions were at a mid-level of abstraction
that doesn't make total sense in this API. Removing them is also
helpful in the general effort to have the attribute system rely less
on `CustomData` internally.
This simplifies the usage of the API and is preparation for #104478.
The `CustomData_add_layer` and `CustomData_add_layer_named` now have corresponding
`*_with_data` functions that should be used when creating the layer from existing data.
Pull Request: blender/blender#105708
Refactoring mesh code, it has become clear that local cleanups and
simplifications are limited by the need to keep a C public API for
mesh functions. This change makes code more obvious and makes further
refactoring much easier.
- Add a new `BKE_mesh.hh` header for a C++ only mesh API
- Introduce a new `blender::bke::mesh` namespace, documented here:
https://wiki.blender.org/wiki/Source/Objects/Mesh#Namespaces
- Move some functions to the new namespace, cleaning up their arguments
- Move code to `Array` and `float3` where necessary to use the new API
- Define existing inline mesh data access functions to the new header
- Keep some C API functions where necessary because of RNA
- Move all C++ files to use the new header, which includes the old one
In the future it may make sense to split up `BKE_mesh.hh` more, but for
now keeping the same name as the existing header keeps things simple.
Pull Request: blender/blender#105416
Multiple user actions performed quickly could be blocked by undo
compacting memory - if the background compacting task was not complete
when the next undo step was pushed.
Notes:
- This and recent improvements to BLI_array_Store gives over ~2x speedup
compared with 3.3x, over 10x compared with 3.4x.
A sub-surfaced cube with the modifier applied was used for testing
(~1.5 million polys), both randomized & non-randomized verts/edge/faces
were used to avoid the sub-surface memory layout biasing the results.
Tested transforming ~1/3rd of the mesh and inverting selection.
- Without compacting mesh-data in parallel, the optimizations to
BLI_array_store can give similar performance to 3.3x, however there
are still cases where performance isn't quite as good - so compact the
arrays in parallel to ensure performance is at least as good as 3.3x.
Resolves#105046.
Currently the shade smooth status for mesh faces is stored as part of
`MPoly::flag`. As described in #95967, this moves that information
to a separate boolean attribute. It also flips its status, so the
attribute is now called `sharp_face`, which mirrors the existing
`sharp_edge` attribute. The attribute doesn't need to be allocated
when all faces are smooth. Forward compatibility is kept until
4.0 like the other mesh refactors.
This will reduce memory bandwidth requirements for some operations,
since the array of booleans uses 12 times less memory than `MPoly`.
It also allows faces to be stored more efficiently in the future, since
the flag is now unused. It's also possible to use generic functions to
process the values. For example, finding whether there is a sharp face
is just `sharp_faces.contains(true)`.
The `shade_smooth` attribute is no longer accessible with geometry nodes.
Since there were dedicated accessor nodes for that data, that shouldn't
be a problem. That's difficult to version automatically since the named
attribute nodes could be used in arbitrary combinations.
**Implementation notes:**
- The attribute and array variables in the code use the `sharp_faces`
term, to be consistent with the user-facing "sharp faces" wording,
and to avoid requiring many renames when #101689 is implemented.
- Cycles now accesses smooth face status with the generic attribute,
to avoid overhead.
- Changing the zero-value from "smooth" to "flat" takes some care to
make sure defaults are the same.
- Versioning for the edge mode extrude node is particularly complex.
New nodes are added by versioning to propagate the attribute in its
old inverted state.
- A lot of access is still done through the `CustomData` API rather
than the attribute API because of a few functions. That can be
cleaned up easily in the future.
- In the future we would benefit from a way to store attributes as a
single value for when all faces are sharp.
Pull Request: blender/blender#104422
With the goal of clearly differentiating between arrays and single
elements, improving consistency across Blender, and using wording
that's easier to read and say, change variable names for Mesh edges
and polygons/faces.
Common renames are the following, with some extra prefixes, etc.
- `mpoly` -> `polys`
- `mpoly`/`mp`/`p` -> `poly`
- `medge` -> `edges`
- `med`/`ed`/`e` -> `edge`
`MLoop` variables aren't affected because they will be replaced
when they're split up into to arrays in #104424.
As part of #95966, move the `ME_SEAM` flag on mesh edges
to a generic boolean attribute, called `.uv_seam`. This is the
last bit of extra information stored in mesh edges. After this
is committed we can switch to a different type for them and
have a 1/3 improvement in memory consumption.
It is also now possible to see that a mesh has no UV seams in
constant time, and like other similar refactors, interacting with
only the UV seams can be done with less memory.
The attribute name starts with a `.` to signify that the attribute,
like face sets, isn't meant to be used in arbitrary procedural
situations (with geometry nodes for example). That gives us more
freedom to change things in the future.
Pull Request #104728
In 6514bb05ea I misinterpreted the function's intended
behavior when there was already an existing active layer. The data from
the active layer is just meat to be copied, the function should always
add a new attribute.
Using spans instead of raw pointers helps to differentiate ararys from
pointers to single elements, gives bounds checking in debug builds, and
conveniently stores the number of elements in the same variable.
Also make variable naming consistent. For example, use `loops` instead
of `mloop`. The plural helps to clarify that the variable is an array.
I didn't change positions because there is a type mismatch between
C and C++ code that is ugly to manage. All remaining code can be
converted to C++, then that change will be simpler.
Pull Request #105138
When implementing the operator to select linked vertices in weight paint mode, the new `AtomicDisjointSet` was used.
In order to keep the code consistent, and also prepare it to add things like Extending/Shrinking selection, the select linked faces logic was also updated.
It now also makes use of the `AtomicDisjointSet` by connecting all edges of each poly. In order to find connecting Faces you then have to check if edges of that poly share a connection.
Pull Request #104577
This reverts commit 19222627c6.
Something went wrong here, seems like this commit merged the main branch
into the release branch, which should never be done.
Cycles uses the "split faces" mesh function to support sharp edges
and auto-smooth. However, 75ad8da1ea updated that
function to ignore the edges that are explicitly tagged as sharp and
only use the edge angle. Fix by taking the attribute into account too.
This patch adds a simple operator to set values of the active
attribute for the selected element. The aim is to give simple control
over attribute values in edit mode rather than to provide the fastest
workflow for most cases. Eventually this operator might be less
important compared to more advanced attribute editing tools, but for
now, exposing a little bit of functionality is low hanging fruit and
will help to see the possibilities.
The implementation mostly consists of boilerplate to register the
necessary property types for the operator and draw their UI.
Beyond that, we just loop over selected elements and set a value.
Pull Request #104426
As described in #95966, replace the `ME_EDGEDRAW` flag with a bit
vector in mesh runtime data. Currently the the flag is only ever set
to false for the "optimal display" feature of the subdivision surface
modifier. When creating an "original" mesh in the main data-base,
the flag is always supposed to be true.
The bit vector is now created by the modifier only as necessary, and
is cleared for topology-changing operations. This fixes incorrect
interpolation of the flag as noted in #104376. Generally it isn't
possible to interpolate it through topology-changing operations.
After this, only the seam status needs to be removed from edges before
we can replace them with the generic `int2` type (or something similar)
and reduce memory usage by 1/3.
Related:
- 10131a6f62
- 145839aa42
In the future `BM_ELEM_DRAW` could be removed as well. Currently it is
used and aliased by other defines in some non-obvious ways though.
Pull Request #104417
Adds two operators to select linked vertices in weight paint mode.
Similar to how it works in edit mode.
Press "L" to select vertices under the cursor,
or CTRL + "L" to select anything linked to the current selection.
Reviewed by: Sybren A. Stüvel, Hans Goudey, Marion Stalke
Differential Revision: https://developer.blender.org/D16848
Ref: D16848