Subdivision Surface: add dependency graph tracking when CPU mesh is needed #104461
No reviewers
Labels
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
5 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#104461
Loading…
Reference in New Issue
No description provided.
Delete Branch "angavrilov/blender:pr-depsgraph-subdiv-cpu"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
After addition of GPU subdivision it is necessary to choose between
using CPU or GPU for a particular object when both ways are technically
possible. Choosing GPU when the mesh is also needed by CPU code would
cause subdivision to be run twice when the CPU mesh is requested by
other code.
This patch adds a simple way to track dependencies that need the CPU
mesh through dependency graph via an already existing mechanism.
Constraints targeting mesh vertex groups, as well as likely modifiers
now tag their targets with a dependency graph flag to notify that the
fully evaluated mesh is needed on the CPU. This is used to disable GPU
subdiv in those cases.
In addition, the evaluated mesh is used by sculpt and paint modes,
so GPU subdivision is disabled in that case too.
One question to consider is the desired behavior for the Geometry Nodes
modifier, since the dependency code doesn't know if the nodes will actually
use the geometry of the object, or only its transformation.
I think it would be better to be conservative and not request the CPU mesh by default. Hopefully in the (probably far) future we'll have a tighter integration with geometry nodes and the depsgraph so this problem could be solved differently. Not exactly sure what that would look like though.
But anyway, I think that's better than making performance much worse whenever just using an object's position.
@ -117,0 +117,4 @@
static bool subsurf_modifier_has_cpu_dependents(const Depsgraph *depsgraph, const Object *ob)
{
/* The sculpt and paint mode UI requires the mesh. */
if (ob->mode & OB_MODE_ALL_SCULPT) {
I can understand why paint mode needs the mesh, but from what I remember about sculpt mode, it doesn't seem to. What am I missing there?
Anything that calls
sculpt_update_object
(e.g. viaBKE_sculpt_update_object_after_eval
) would access the mesh. It is possible that code retrieves the mesh even when it doesn't need it and can be improved, but that is probably out of the scope of this patch.One thing though, this code here probably should check
DEG_is_active
too - the location calling toBKE_sculpt_update_object_after_eval
does check it.@ -429,1 +428,3 @@
uiItemL(layout, "Autosmooth or custom normals detected, disabling GPU subdivision", ICON_INFO);
if (BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(depsgraph, ob, mesh, smd)) {
uiItemL(layout,
"Disabling GPU subdivision due to autosmooth, custom normals or dependencies",
I'm not sure an optimization like this deserves a UI label. If there is a way to show whether GPU subdivision is being used, it should probably be more subtle IMO.
Well, I wasn't the one who put this here, I just change the text to reflect my additions ;)
Custom normals are incompatible with subdivision surfaces. The fact that GPU subdivision is disabled in the presence of such normals is to start a differentiation between workflows with custom shading and workflows with subdivision surfaces. See #68891 and #68893. This is what this UI label is for. Essentially to put in users mind that subdivision and custom normals should be different workflows. It only affects GPU subdivision as it is easier/more acceptable to prevent new features from introducing "bad" workflows than breaking compatibility.
If you really mean this, rather than just simplifying the phrase 'the GPU implementation of subdivision surfaces', I think the NPR people will very much beg to differ. In fact, the subdivision surface modifier specifically has an option to subdivide and interpolate custom normals.
In my view the purpose of the message is to let the user know when the GPU optimization won't be used, so they can be aware and plan accordingly. IIRC something similar happened in 2.7* versions. In #104441 I even added a message tracking the internal state when it is actually being used for feedback.
Will this somehow help with #102012, #102127?
I think it was most likely largely helped by #104441 already. This would produce further improvement, but smaller in comparison to that one.
ac2a835af4
tob815f2bc92
Yes, it really helped in both cases and + one more, I couldn't find the report, the problem was with a very large slowdown in operations with shape keys, when the GPU Subdivision was turned on
I am not sure why the geometry nodes are different from the modifiers in this regard. The modifiers explicitly desitinguish transform from geometry components using
DEG_OB_COMP_TRANSFORM
andDEG_OB_COMP_GEOMETRY
components passed to theDEG_add_object_relation()
. I'd imagine the geometry nodes can (and should) do the same thing.Not sure what is the exact proposal of how to achieve this?
As for the implementation of this patch, things like
DEG_add_collection_geometry_special_eval_flag(ctx->node, col, DAG_EVAL_NEED_CPU_SUBSURF);
seems far to specific. What if we add other GPU-side modifiers?And why do we need such explicit flag?
Ideally I'd imagine that the modifier will provide capability that it can be evaluated on GPU, and then the dependency graph can provide information about where the modifier is to be evaluated.
Until then I do not really see why can't we imply that dependency on the geometry component means the geometry is to exist on the CPU side.
Marking as
Requested changes
since the design of the solution does not really seem optimal and at least requires much better explanation on the decision.Because the Geometry Nodes modifier currently only knows that an object is referenced, and has no idea what the object is used for. It's possible the actual nodes only access the transform, for instance; or the node may not even be connected to the output at all and not evaluated.
Maybe rename to
DAG_EVAL_NEED_CPU_EVALUATED_MESH
?Because it does not mean that. For one, there are modifiers like Collision which save a snapshot of a particular point in the modifier stack, and all physics collision dependencies want GEOMETRY to ensure it is evaluated, but don't care about the final evaluated mesh.
From the design perspective of the dependency graph relation means data dependency.
The collision case you're mentioning is kinda a violation of this design, and I'd rather see that un-entagled than adding a fragile low-level band-aid.
If the collision relation will point to the collision modifier instead of the component the benefits you're gaining are:
We might also introduce a relation flag to facilitate the collision relations builder if needed.
b815f2bc92
to42dd5bc091
42dd5bc091
to7d5a6e7caf
I renamed the flag to DAG_EVAL_NEED_CPU_EVALUATED_MESH to make it more generic.
The flag is providing this information, though.
This won't work, because there almost always are dependencies on the geometry component, e.g.
DIMENSIONS()
,GEOMETRY_EVAL_DONE()
of a collection,DUPLI()
etc. In the case of simple instancing, none of these need the cpu mesh, so a special flag is necessary in any case. In case of rigid body, there is even an option to use the deform-only mesh for collision.The only question is whether the flag should be attached to the object like in this implementation, or the relation (possibly with the default being 'needs everything' and the flag marking relations that don't) and then propagated to an object status somehow.
However it does not mean a dependency on the complete evaluated mesh.
Currently it can't work because modifier nodes are dummies and the actual evaluation happens in
GEOMETRY_EVAL()
.As mentioned before, dependency on geometry does not mean dependency on the fully evaluated mesh on CPU.
Subdivision Surface: add dependency graph tracking when cpu mesh is needed.to Subdivision Surface: add dependency graph tracking when CPU mesh is neededFor
DIMENSIONS
and collection'sGEOMETRY_EVAL_DONE
and can (and probably should) to introduce the other type of relations which will mean "evaluation order only".The
DUPLI
I do not remember from the top of my head the exact topology, but dupli-verts will need the final evaluated mesh.For the rigid body I'd rather have a solution in the
DepsgraphRelationBuilder::build_rigidbody
which will align relations better with the actual usage of the dependencies with the solver: if the solver does not access the final evaluated mesh it should not add relation to the final state.Those kind of solver dependencies were always a mess, and nowadays we can do much better job in routing the relations properly.
Long story short: I'd really like to see an effort of solving the root causes in a more localized areas.
This is all moot while modifier evaluation actually happens in
GEOMETRY_EVAL()
. While evaluation works in the same as it does now, it is completely impossible to decouple dependencies on different parts of the evaluated state.In case of rigid body specifically, there is an option that specifies which version of the mesh it uses for collision, and the default is actually the Deform Only evaluated mesh. It is thus bound to the same
GEOMETRY_EVAL
bottleneck as snapshotting modifiers like collision.I am not sure why its considered really completely impossible.
To me it seems that it is possible to do some (conceptually) simple modifications in the graph to handle the physics relations more properly.
For example, you can add a
GEOMETRY_FINAL
exit no-op operation for the geometry component (wich will be executed after theGEOMETRY_EVAL
), and route relations which needs the final evaluated mesh to it. Operations which do not need final state but something that is evaluated as a part of modifier stack (like, orco or deform-only) will still point to theGEOMETRY_EVAL
.Well, let's say it requires changes to the dependency graph that are beyond my understanding of the overall design, so I need design suggestions from somebody like you.
That could work, but:
I would do it on the depsgraph issue, as the post-build pass to see if there are links coming from the
EVAL_DONE
node in the geometry component to other IDs.I am not really sure what implicit relations those are.
Yeah, those would need some indirection check.
The collection geometry is used to allow modifiers referencing collection as geometry. It was done for the boolean modifiers: https://archive.blender.org/developer/D11053
Would need to do some follow-the-link logic for those to see if a collection geometry is actually used by anything than other collections. A bit annoying, but seems straighfroward and centralized enough.
Checkout
From your project repository, check out a new branch and test the changes.