### Problem Description
Driver functions written in Python have access to neither the context nor the dependency graph that is evaluating the driver. As a result, it is not possible to reliably obtain the current view layer. Accessing `bpy.context.view_layer` is not a valid option here (see [T75553](https://developer.blender.org/T75553)), as there could be multiple view layers being evaluated at once (one rendering and one being shown in the viewport, for example).
### Proposed Solution
I think that conceptually the nicest solution for this is to make the currently evaluating depsgraph available to drivers. This can be done by passing it in the same way as we pass other driver variables, in `BPY_driver_exec()`. The driver "namespace" is not directly suitable for this, as it is a global object and thus has the same issues as accessing `bpy.context`.
To make `BPY_driver_exec()` aware of the current depsgraph, I see a few possible approaches:
- Pass a `Depsgraph *` as parameter all the way down to the `BPY_driver_exec()` call. This is conceptually the simplest solution, but it does require changing a lot of functions (see the call tree below). This approach can be broken down into:
- Add a new `Depsgraph *` parameter to each function.
- Replace the `float time` parameters with a `Depsgraph *`, and use the depsgraph to obtain the time. This looks nice, but the evaluation time of the depsgraph and of the animation system can be different (for example when using the 'Animated Strip Time' of an NLA strip).
- Bundle the `Depsgraph *` and the `float time` into a new struct, and pass that instead of the `time` parameter.
- Use a thread-local global variable to store the current `Depsgraph *`. This avoids making changes to a lot of functions. However, given that people have worked hard to remove as much `G.main` from Blender's codebase, I don't think adding new globals is the way forward. Furthermore, this would require very careful consideration when creating and destroying dependency graphs.
- Convert the animation code to C++, so that a more object-oriented model can be used, and the `Depsgraph *` stored in a member variable rather than passed to each function.
### Call tree of `BPY_driver_exec`
The `BPY_driver_exec()` function is called by `evaluate_driver_python()`, etc. Every indentation level means "is called by". Functions are only listed once.
- `BPY_driver_exec(time)`
- `evaluate_driver_python(time)`
- `evaluate_driver(time)`
- `evaluate_fcurve_driver(time)`
- `calculate_fcurve(time)`
- `animsys_evaluate_fcurves(time)`
- `animsys_evaluate_action_ex(time)`
- `animsys_evaluate_action(time)`
- `BKE_animsys_evaluate_animdata(time)`
- `what_does_obaction(time)`
- `actcon_get_tarmat(depsgraph)`
- `BKE_animsys_evaluate_all_animation(depsgraph)`
- `BKE_animsys_eval_animdata(depsgraph)`
- `nlastrip_evaluate_controls(time)`
- `nlastrips_ctime_get_strip(time)`
- `nlastrip_evaluate_meta()` with time = strip-dependent
- `nlastrip_evaluate()`
- `nlastrip_evaluate_transition()`
- `animsys_evaluate_nla(time)`
- `animsys_calculate_nla(time)`
- `BKE_animsys_get_nla_keyframing_context(time)`
- `achannel_setting_slider_cb(context)`
- `achannel_setting_slider_shapekey_cb(context)`
- `insert_keyframe(time)`
- `insert_key_button_exec(context)`
- `ED_autokeyframe_property(context)`
- `insert_action_keys(bAnimContext)`
- `insert_graph_keys(bAnimContext)`
- `autokeyframe_object(bAnimContext)`
- `autokeyframe_pose(bAnimContext)`
- `pyrna_struct_keyframe_insert(NOTHING)` (no context available)
- `animsys_evaluate_drivers(time)`
- `animsys_evaluate_action_group(time)`
- `poselib_apply_pose(time)`
- `poselib_preview_apply(context)`
- `BKE_animsys_eval_driver(depsgraph)`
- `fcurve_is_changed(time)`
- `ui_but_anim_flag(time)`
- `UI_context_update_anim_flag(context)`
- `UI_block_end_ex(context)`
- `insert_keyframe_value(time)`
- `insert_keyframe_direct(time)`
- `insert_keyframe_fcurve_value(time)`
`bAnimContext` objects are created by `ANIM_animdata_get_context(context)`, so they could be extended with a `Depsgraph *` from the context.