Fix #104798: Slow frame-change & scrubbing with many objects #104801
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
4 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#104801
Loading…
Reference in New Issue
No description provided.
Delete Branch "ideasman42/blender:pr-scene-collection-skip-on-cow"
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?
Avoid re-copying the scene when the scene is tagged for frame change.
For scenes with many objects scrubbing & jumping between first/last caused noticeably worse performances.
Resolve by:
@blender-bot build
@blender-bot build linux
23857dc29c
to3e4349f036
All the node tress regardless of whether they are "embedded" into a "parent" datablock are treated as a "stand-alone" ID data-blocks in the dependency graph builder. This takes care of ensuring that:
The goal of the special cases for the scene builder was to avoid special cases in the dependency graph nodes and relations builders, at a cost of special tricks of during copy-on-write and during tagging.
The proposed patch is based on a case which solves different problem, and does not fully implement the case it is based on. Not going into details: the evaluated scene will always point to the original
master_collection
, which is violation of the original/evaluated state design.A proper solution would be to make it so that
NodeType::AUDIO
does not involve the copy-on-write tag for theD_RECALC_FRAME_CHANGE
tag.The most straightforward way it seems to be to make it so
IDRecalcFlag
is passed toneed_tag_cow_before_update
, and have an implementation ofAudioComponentNode
which will returnfalse
if thetag == ID_RECALC_FRAME_CHANGE
.Marking as requested changes.
I'm aware of this and checked to make sure this wasn't happening, attached a patch that adds a print to
deg_expand_copy_on_write_datablock
, in my tests it's never sharing the pointer. Is there another point in the code where the pointers would be shared?If you're aware that this code violates an existing design, that should be loudly warned about in the description, and not left as an exercise for the reader.
Also I don't think that adding a
printf()
somewhere and not seeing it print anything during testing is enough of a motivation to move away from an established design.Please always give all the information you have when presenting a patch. Especially when it does not use things the way they are intended to.
I also would not trust the prints at a specific snapshot of code. We should not base any design on the specific behavior of another area, without ensuring that the behavior is there by design.
The only reason why the evaluated ID for the
master_collection
is created which I can think of is that the built-in into scenemaster_collection
is references by a layer collection. It is hard to see from the code (this is why clear design are essential). But if that is true, then we should indeed treat themasetr_collection
the same way as thenodetree
. Otherwise we are probably making a mess from life time of objects and memory usage. But that would mean bug fix in the depsgraph handlingmaster_collection
and not the speedup.For the actual speedup we do need to avoid copy-on-write as much as possible, because one also does not want to do the ID remapping routines (which this patch does not address at all).
As far as I can see it's not violating any existing design (as in I checked to make sure it's not sharing pointers).
As I understand it - the
master_collection
is an embedded ID, copying the COW scene already copies the ID, so it makes sense to treat this the same as other embedded ID's.My impression was this is using the API the way it's intended - as it's following a workaround used for many other embedded ID data-blocks.
Fair enough, however duplicating scene (the COW copy) always duplicates the
master_collection
so as far as I can see this will never share a pointer with the original data.The embedded collection shouldn't be referenced by anything except for the scene (it's not stored in
G_MAIN->collections
for e.g.)Which area are you referring to?
This patch updates
ntree_hack_remap_pointers
&scene_foreach_id
usesBKE_library_foreach_ID_embedded
forscene->master_collection
.Yeah, something that i guess could have been described better in the comment above.
Basically, the dependency graph handles the "embedded" IDs the same way as non-embedded onces. This means, for example, that node tree relation builder does not destinguish non-embedded node groups from embedded compositor/shader. And the copy-on-write takes care of remapping the "embedded" pointers to the, what appears to be non-embedded from the depsgraph perspective, ID.
In practice this means that the graph builder and the copy-on-write update step needs to make the same (weak) assumptions.
I don't really understand how this works.
First of all, in the case of embedded node trees we do not want the ID copy function to duplicate or allocate that pointer. The depsgraph takes care of assigning it to a proper evaluated state.
The code in the patch temporarily assigns the
master_collection
tonullptr
, and then calls the ID copy function, and restores the pointer back. If the ID copy function allocatesmaster_collection
then there is a memory leak. But in any case, themaster_collection
is restored to its original value.In the case of embedded node trees it is the
BKE_library_foreach_ID_link()
+foreach_libblock_remap_callback()
which takes care of remapping the embedded pointer to an evaluated node ID pointer from the depsgraph.If the
master_collection
follows the same exact code as the embedded node trees and it has different pointer in the evaluated scene it means that the master collection somehow got created in the dependency graph.Thing is: unlike the embedded node trees for scene compositor and material shader the dependency graph builder does not access
scene->master_collection
at all. So, if there is no such explicit access where does the ID node for themaster_collection
is coming from?Which leads to the next point...
So I tohught as well.. However. Without going deep into code or trying to find an actual design, lets use a trusty old
printf
way of checking the obvious suspect:view_layer->layer_collections
.Sure enough, the output is:
So is it by design? Is it always guaranteed that the first layer collection references embedded
master_collection
?The entire copy-on-write can/should be skipped on the frame change. Dependency graph's
DEG_evaluate_on_framechange
takes care of updating the frame value. Doing this Scene datablock free + duplicate +BKE_library_foreach_ID_embedded
is not needed at all.It could as simple as making it so
Audio
component returnsfalse
from itsneed_tag_cow_before_update
, at least on a frame change. For volume changes we still might want to copy-on-write to grab the new value of volume.This sounds more logical/correct behavior of frame change handling, and it solves the root of the problem stated in the description: the
ID_RECALC_FRAME_CHANGE
causing heavy scene copy-on-write.Long story short: if copy-on-write is not needed, don't do it at all.
3e4349f036
tof9ddbce145
Confirmed that skipping the COW tag for Audio components fixes the issue on frame change, so if COW isn't needed for anything else - this fixes #104798.
Skipping the collection copy still seems worthwhile though, practically all scene settings (some material shading settings) are causing the collection to be duplicated (so changing the render-resolution or scene samples duplicates the collection and rebuilds it's hash on each redraw - which can cause a noticeable slowdown).
I wasn't aware the
master_collection
can be referenced fromLayerCollections
. As long as theLayerCollection
is part of the scene - I think this could be supported without causing problem however that needs to be investigated in more detail.Updated the patch to change Audio tagging not to copy-on-write as suggested.
@blender-bot build linux
The copy-on-write is only obviously not needed for the
ID_RECALC_FRAME_CHANGE
, as the dependency graph is taking care of the frame change. For other types the dependency graph does not ensure anything, so other tags might still need copy-on-write to happen. See my comment above where Iv'e mentioned this.For example
ID_RECALC_AUDIO_MUTE
andID_RECALC_AUDIO_LISTENER
definitely need copy-on-write.The
ID_RECALC_AUDIO_VOLUME
andID_RECALC_AUDIO_FPS
are a bit more tricky. If those flags will not imply copy-on-write nothing will immediately break. But! This is only because of they're used in combination withID_RECALC_SEQUENCER_STRIPS
. Arguably, this combination is wrong and the tag should only happen for VOLUME and FPS, and then the tag is to be flushed to the sequencer components. In any case, designing component copy-on-write component based on the current state of flags used to tag is weak, and we should not do so.For the record, it seems that Sergey had some remarks that haven't resulted in a change of this PR yet. I was actually waiting for that to happen before diving into the code myself.
Is this still relevant PR?
f9ddbce145
to0a4907dae6
The issue described in #104798 still exists.
Updated the PR & description with the change Sergey suggested (passing a recalc flag to
AudioComponentNode::need_tag_cow_before_update
).This didn't fix the problem on it's own though,
deg_graph_tag_parameters_if_needed
also needed to excludeID_RECALC_FRAME_CHANGE
fromclean_flags
, which is correct as far as I can see since the depsgraph writes into the COW scenes current frame directly.@blender-bot build
Apart from a few small remarks (see inline notes) the code LGTM.
I'm having a harder time correlating the results to the behaviour described in #104798, though.
USE_SCENE_COLLECTION = False
USE_SCENE_COLLECTION = True
So yes, this patch seems to increase performance quite considerably 👍
I can't seem to reproduce the issue in the bug report, though, as for me both 'scene collection' and 'other collection' cases are equally fast.
I tested this PR against
8a4c45a202
, which seems to be the parent commit when I pull this PR.Update: the script to reproduce the issue from #104798 doesn't include audio, though, so I also don't feel that it is sufficient to test the changes in this PR. @ideasman42 how did you test? Can we reproduce that?
@ -241,1 +240,4 @@
/* Audio component. */
struct AudioComponentNode : public ComponentNode {
virtual bool need_tag_cow_before_update(IDRecalcFlag tag) override
const IDRecalcFlag flag
@ -242,0 +244,4 @@
{
/* Frame change doesn't require a copy of the scene, doing so can be a heavy operation
* especially when the collection contains many objects, see #104798. */
if (tag == ID_RECALC_FRAME_CHANGE) {
Personally I'd prefer
return tag != ID_RECALC_FRAME_CHANGE;
No strong feelings, it mostly depends on how likely it is that other cases will be added. If you keep the
if
, I think it's better to put the explanation inside the conditional block.0a4907dae6
to8541e4808e
Interesting, I wasn't aware of this performance difference, when updating the patch I was just checking the slow case was faster, but the difference in performance doesn't depend much on
USE_SCENE_COLLECTION
anymore and there is a speedup in both cases on my system too.Increasing performance for both cases, changed between 3.6 & 4.0 (where there is a big difference in performance in 3.6 but not in 4.0 and newer), noted in #104798.
@dr.sybren audio can be tested by manually adding it to the sequencer, scrubbing with the cursor & arrow keys works as before. Animated audio settings could depend on having a scene copy although this seems to be broken (animating the scenes volume never updates & looks to be set at the volume when playback starts, even the
SOUND_OT_update_animation_flags
operator doesn't seem to be working).Fix #104798: Slower frame-change with many objects in the scenes collectionto Fix #104798: Slow frame-change & scrubbing with many objects8541e4808e
tod3490494bb
@blender-bot build
@ideasman42 On the code side I think it is implementing all the things we've discussed before, and that part seems fine now. I run tests with some of anim files we've got, and all of them seem to work correctly.
I did not see performance impact on the production scenes, but with the setup from the original report (created by a script) there is quite measurable boost in FPS. And logically AUDIO should be causing copy-for-eval on frame change.
The thing which would be nice to clarify is this:
Do you mean it is already broken before this PR, or is it broken with this PR and more work is needed?
It's already broken before this PR, reported the bug #120726.
It looks like
SOUND_OT_update_animation_flags
isn't called anywhere, yet the flags it sets are expected to be used for animated audio to work properly.Thanks for clarification. I don't think that issue should be holding off this PR.