It's not so much happening inside the lock and using spin
lock instead of mutex lock will give some speedup due to
smaller latency of resuming the thread when mutex was locked.
Initially i wanted to have some really simple and basic
threading scheduler and wrote one based on traversing
depsgraph in advance. But it ended up in some issues with
the single-pass traverse i did which didn't gather all
the dependencies actually.
That was for sure solvable, but it ended up in a bit of
time consuming thing and with huge help of Brecht's
patch it was faster just to write proper balancing.
But it's again really basic thing, which could be
easily changed depending on feedback and design decisions
from Joshua,
So for now it works in the following way:
- Currently DagNode is used for threaded evaluaiton,
meaning traversing actually happens for DagNodes.
This is easier than converting DAG to a graph where
only objects are stored, but required adding one int
field to DagNode for faster runtime checks.
We could change this later when it'll be clear how
and where we'll store evaluation data, but for now
it work pretty ok.
- The new field is called "valency" and it's basically
number of node parents which needs to be evaluated
before the node itself could be evaluated.
- Nodes' valency is getting initialized before threading,
and when node finished to update valency of it's childs
is getting decreased by one. And if it happens so
child's valency became zero, it's adding to task pool.
- There's thread lock around valency update, it'll be
replaced with spinlock in nearest future.
- Another update runtime data is node color. White nodes
represents objects, gray one non-objects.
Currently it's needed to distinguish whether we need to
call object_handle_update on node->ob or not. In the
future it could be replaced with node->type to support
granularity, meaning we then could update object data
separately from object itself.
- Needed to add some public depsgraph functions to make
it possible to traverse depsgraph without including
depsgraph private header to other files.
This change doesn't make code anyhow more stable, but
solves update order issues noticed while working on
fixing underlying bugs.
Threaded update is still ifdef-ed for until curves and
armatures are considered thread-safe, which is next
step to be done.
Patch by Brecht, which in original version also
gets rid of ThreadedWorker in favor of new task
scheduler and ports some areas to it.
Kudos to Brecht for this work!
tweakmode, this will now result in tweakmode being exited instead of going into
a weird limbo-land where channel selection has changed (but tweakmode is still
active but not drawn)
Selection state of F-Curves is lost when resizing the Graph Editor.
The problem was that SIPO_TEMP_NEEDCHANSYNC was getting set in the graph_init()
callback, which gets called everytime the view resizes, and not just the very
first time this happens. However, setting this flag forces the selection state
to the updated/pulled from the scene data.
In the past, it was necessary to set this flag so that we could force F-Curve
colors to get initialised correctly. However, things probably changed at some
point, so this behaviour is no longer needed. At worst now, opening a new graph
editor may not show F-Curve selection correctly synced with the viewport, though
that's easily worked around by reselecting whatever it is in the 3d view.
This was one of the consequences of r.57333 (i.e. influence shouldn't be ignored
on the first strip that animates a channel), as scale should really default to a
base value of 1 (instead of things being blended against 0 as per all other
properties). The end result was that bones were getting scaled to zero here when
the influence of their strip fell to zero.
Now, we use the RNA default values of properties to initialise their initial
values. This may/may not work well in all cases:
1) For properties which don't have the appropriate RNA defaults set, this will
be problematic. But, most properties people are likely to animate here I think
are already set up correctly.
2) It may not always be nice to have values "snapping back" to default values.
In this case, you should still be defining a strip at the bottom of your NLA
stack which defines what the appropriate rest poses *should* be for your shot.
using "Auto Keying" + "Insert Available Only"
Patch from Campbell.
The problem was that NLA offset/mapping correction was only done when no
destination action was supplied to insert_keyframe(). In most cases, this is not
a problem, since all normal keyframing goes through keyingset or the insert-
button operators, and these just pass action=NULL (since they're too lazy to
look it up). However, there is one situation where this bug gets triggered (the
specific combination of autokeyframing and "insert available only"), where the
caller of insert_keyframe() actually passed in an action (to prevent it from
creating one itself!).
This was caused by r.57812
There were two problems here:
1) vertex_group_vert_select_unlocked_poll() had faulty logic which meant that
it always failed when there were no vgroups present yet - the final return
always just fell through
2) Since the "Assign to New Groups" option was actually implemented using the
same operator as "Assign to Active Group" (just with an extra parameter set), if
the active group was locked, it was not possible to "Assign to New Group" (even
though a new group would not be locked).
Move static variables to context filling in by this fcuntion
and owned by a callee function. This ensures no conflicts
between threads happens because of static variables used in
this function.
Also moved modifier types and virtual modifiers data to a
function called from creator. This is needed to be sure all
the information is properly initialied to the time when
threads starts to use this data.
Make Local operator uses BKE_library_make_local function if all the
datablocks needs to be made local. And this function was calling
id_clear_lib_data for every datablock, which only clears library
data. But this function doesn't work correct for datablocks which
areshared by multiple users (this is also mentioned in comment
for this function).
This lead to situations when two datablocks shares the same runtime
data leading to crashes later. For example making everythig local in
scales cycles scene from durian ends up in a crash when toggling
rig edit mode.
Solved by using id_make_local instead of id_clear_lib_data, which
will ensure all the data are nicely expanded and made local.
Checked by Brecht, thanks fr the review!
This commit contains changes related on running function
BKE_object_handle_update_ex from multiple threads in order
to increase scene update time when having multiple
independent groups of objects.
Currently this required changes to two areas:
- scene.c, where scene_update_tagged_recursive is now using
threads for updating the object
There're some tricks to prevent threads from being spawned
when it's not needed:
* Threading will only happen if there're more than one CPU
core.
* Threading will happen only if there're more than single
object which needed to be updated.
There's currently one crappy part of the change: which is
freeing object caches (derivedFinal, derivedDeform and so)
from main thread. This is so because in case VBO are used
freeing DM is not thread safe. This is because DrawObject
used global array. Would look into possibility of making
that code safe later.
There're also currently some ifdef-ed debug-only code, which
helps a lot troubleshooting whether everything is working
fine. This code looks a bit ugly now, will either drop it
later or make it more cleat.
And one more thing: threaded update is CURRENTLY DISABLED.
This is because of some thread-unsafe issues discovered
while was working on this patch. Namely:
* I have once a crash in Curve module. Wasn't been able
to reproduce the crash, but could thing about some
unsafe code there.
* Virtual modifier list is not thread-safe (it uses static
variables).
* Armature modifier is also doesn't seem to be thread safe
because of storing some temporary runtime data in actual
armature.
All this issues are to be solved next.
- depsgraph.c, where i've added a function which gives list
of groups, each group contains objects and dependency is
only allowed between objects inside one group.
This is needed to make scheduling of objects easier, which
means update threads will operate on groups, and will handle
objects one-by-one inside group. Different threads will
operate on different groups.
Currently such groups will be generated on every update.
Actually, on every run of scene_update_objects_threaded which
only happens if there're objects marked for update. In the
future we could consider storing such groups in graph itself,
which will help saving CPU power on building such groups.
But this is something to be discussed with Joshua first.
P.S. If you really want to test threaded update, you'll
need to replace:
#undef USE_THREADED_UPDATE
with:
#define USE_THREADED_UPDATE
Now it's possible to mark operator as safe to be used
in locked interface mode by adding OPTYPE_ALLOW_LOCKED
bit to operator template flags.
This bit is completely handled by wm_evem_system, not
with operator run routines, so it's still possible to
run operators from drivers and handlers.
Currently allowed image editor navigation and zooming.