Files
test2/source/blender/depsgraph/DEG_depsgraph.hh
Jacques Lucke 2d2b087fcf Geometry Nodes: support baking data block references
With this patch, materials are kept intact in simulation zones and bake nodes
without any additional user action.

This implements the design proposed in #108410 to support referencing
data-blocks (only materials for now) in the baked data. The task also describes
why this is not a trivial issue. A previous attempt was implemented in #109703
but it didn't work well-enough.

The solution is to have an explicit `name (+ library name) -> data-block`
mapping that is stored in the modifier for each bake node and simulation zone.
The `library name` is necessary for it to be unique within a .blend file. Note
that this refers to the name of the `Library` data-block and not a file path.
The baked data only contains the names of the used data-blocks. When the baked
data is loaded, the correct material data-block is looked up from the mapping.

### Automatic Mapping Generation

The most tricky aspect of this approach is to make it feel mostly automatic.
From the user point-of-view, it should just work. Therefore, we don't want the
user to have to create the mapping manually in the majority of cases. Creating
the mapping automatically is difficult because the data-blocks that should
become part of the mapping are only known during depsgraph evaluation. So we
somehow have to gather the missing data blocks during evaluation and then write
the new mappings back to the original data.

While writing back to original data is something we do in some cases already,
the situation here is different, because we are actually creating new relations
between data-blocks. This also means that we'll have to do user-counting. Since
user counts in data-blocks are *not* atomic, we can't do that from multiple
threads at the same time. Also, under some circumstances, it may be necessary to
trigger depsgraph evaluation again after the write-back because it actually
affects the result.

To solve this, a small new API is added in `DEG_depsgraph_writeback_sync.hh`. It
allows gathering tasks which write back to original data in a synchronous way
which may also require a reevaluation.

### Accessing the Mapping

A new `BakeDataBlockMap` is passed to geometry nodes evaluation by the modifier.
This map allows getting the `ID` pointer that should be used for a specific
data-block name that is stored in baked data. It's also used to gather all the
missing data mappings during evaluation.

### Weak ID References

The baked/cached geometries may have references to other data-blocks (currently
only materials, but in the future also e.g. instanced objects/collections).
However, the pointers of these data-blocks are not stable over time. That is
especially true when storing/loading the data from disk, but also just when
playing back the animation. Therefore, the used data-blocks have to referenced
in a different way at run-time.

This is solved by adding `std::unique_ptr<bake::BakeMaterialsList>` to the
run-time data of various geometry data-blocks. If the data-block is cached over
a longer period of time (such that material pointers can't be used directly), it
stores the material name (+ library name) used by each material slot. When the
geometry is used again, the material pointers are restored using these weak name
references and the `BakeDataBlockMap`.

### Manual Mapping Management

There is a new `Data-Blocks` panel in the bake settings in the node editor
sidebar that allows inspecting and modifying the data-blocks that are used when
baking. The user can change what data-block a specific name is mapped to.

Pull Request: https://projects.blender.org/blender/blender/pulls/117043
2024-02-01 09:21:55 +01:00

293 lines
10 KiB
C++

/* SPDX-FileCopyrightText: 2013 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup depsgraph
*
* Public API for Depsgraph
*
* Dependency Graph
* ================
*
* The dependency graph tracks relations between various pieces of data in
* a Blender file, but mainly just those which make up scene data. It is used
* to determine the set of operations need to ensure that all data has been
* correctly evaluated in response to changes, based on dependencies and visibility
* of affected data.
* Evaluation Engine
* =================
*
* The evaluation takes the operation-nodes the Depsgraph has tagged for updating,
* and schedules them up for being evaluated/executed such that the all dependency
* relationship constraints are satisfied.
*/
/* ************************************************* */
/* Forward-defined typedefs for core types
* - These are used in all depsgraph code and by all callers of Depsgraph API...
*/
#pragma once
#include "DNA_ID.h"
/* Dependency Graph */
struct Depsgraph;
/* ------------------------------------------------ */
struct Main;
struct Scene;
struct ViewLayer;
enum eEvaluationMode {
DAG_EVAL_VIEWPORT = 0, /* evaluate for OpenGL viewport */
DAG_EVAL_RENDER = 1, /* evaluate for render purposes */
};
/* DagNode->eval_flags */
enum {
/* Regardless to curve->path animation flag path is to be evaluated anyway,
* to meet dependencies with such a things as curve modifier and other guys
* who're using curve deform, where_on_path and so. */
DAG_EVAL_NEED_CURVE_PATH = (1 << 0),
/* A shrinkwrap modifier or constraint targeting this mesh needs information
* about non-manifold boundary edges for the Target Normal Project mode. */
DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY = (1 << 1),
};
/* ************************************************ */
/* Depsgraph API */
/* -------------------------------------------------------------------- */
/** \name CRUD
* \{ */
/* Get main depsgraph instance from context! */
/**
* Create new Depsgraph instance.
*
* TODO: what arguments are needed here? What's the building-graph entry point?
*/
Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode);
/**
* Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph.
* Used for:
* - Undo steps when we do want to re-use the old depsgraph data as much as possible.
* - Rendering where we want to re-use objects between different view layers.
*/
void DEG_graph_replace_owners(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
ViewLayer *view_layer);
/** Free graph's contents and graph itself. */
void DEG_graph_free(Depsgraph *graph);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Types Registry
* \{ */
/** Register all node types. */
void DEG_register_node_types();
/** Free node type registry on exit. */
void DEG_free_node_types();
/** \} */
/* -------------------------------------------------------------------- */
/** \name Update Tagging
* \{ */
/** Tag dependency graph for updates when visible scenes/layers changes. */
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, bool do_time);
/** Tag all dependency graphs for update when visible scenes/layers changes. */
void DEG_tag_on_visible_update(Main *bmain, bool do_time);
/**
* \note Will return NULL if the flag is not known, allowing to gracefully handle situations
* when recalc flag has been removed.
*/
const char *DEG_update_tag_as_string(IDRecalcFlag flag);
/** Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(ID *id, unsigned int flags);
void DEG_id_tag_update_ex(Main *bmain, ID *id, unsigned int flags);
void DEG_graph_id_tag_update(Main *bmain, Depsgraph *depsgraph, ID *id, unsigned int flags);
/**
* Tag the given ID for an update in the given depsgraph even though it evaluated state might not
* have changed. This can be used when some data is required that is generated as a side effect of
* the evaluation. For example, baking an intermediate geometry in geometry nodes needs this,
* because the to-be-baked geometry has to be recomputed even though no input changed and the final
* geometry also did not change.
*/
void DEG_id_tag_update_for_side_effect_request(Depsgraph *depsgraph, ID *id, unsigned int flags);
/** Tag all dependency graphs when time has changed. */
void DEG_time_tag_update(Main *bmain);
/** Tag a dependency graph when time has changed. */
void DEG_graph_time_tag_update(Depsgraph *depsgraph);
/**
* Mark a particular data-block type as having changing.
* This does not cause any updates but is used by external
* render engines to detect if for example a data-block was removed.
*/
void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type);
void DEG_id_type_tag(Main *bmain, short id_type);
/**
* Set a depsgraph to flush updates to editors. This would be done
* for viewport depsgraphs, but not render or export depsgraph for example.
*/
void DEG_enable_editors_update(Depsgraph *depsgraph);
/** Check if something was changed in the database and inform editors about this. */
void DEG_editors_update(Depsgraph *depsgraph, bool time);
/** Clear recalc flags after editors or renderers have handled updates. */
void DEG_ids_clear_recalc(Depsgraph *depsgraph, bool backup);
/**
* Restore recalc flags, backed up by a previous call to #DEG_ids_clear_recalc.
* This also clears the backup.
*/
void DEG_ids_restore_recalc(Depsgraph *depsgraph);
/** \} */
/* ************************************************ */
/* Evaluation Engine API */
/* -------------------------------------------------------------------- */
/** \name Graph Evaluation
* \{ */
enum DepsgraphEvaluateSyncWriteback {
DEG_EVALUATE_SYNC_WRITEBACK_NO,
/**
* Allow writing back to original data after depsgraph evaluation. The change to original data
* may add new ID relations and may tag the depsgraph as changed again.
*/
DEG_EVALUATE_SYNC_WRITEBACK_YES,
};
/**
* Frame changed recalculation entry point.
*
* \note The frame-change happened for root scene that graph belongs to.
*/
void DEG_evaluate_on_framechange(
Depsgraph *graph,
float frame,
DepsgraphEvaluateSyncWriteback sync_writeback = DEG_EVALUATE_SYNC_WRITEBACK_NO);
/**
* Data changed recalculation entry point.
* Evaluate all nodes tagged for updating.
*/
void DEG_evaluate_on_refresh(
Depsgraph *graph,
DepsgraphEvaluateSyncWriteback sync_writeback = DEG_EVALUATE_SYNC_WRITEBACK_NO);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Editors Integration
*
* Mechanism to allow editors to be informed of depsgraph updates,
* to do their own updates based on changes.
* \{ */
struct DEGEditorUpdateContext {
Main *bmain;
Depsgraph *depsgraph;
Scene *scene;
ViewLayer *view_layer;
};
using DEG_EditorUpdateIDCb = void (*)(const DEGEditorUpdateContext *update_ctx, ID *id);
using DEG_EditorUpdateSceneCb = void (*)(const DEGEditorUpdateContext *update_ctx, bool updated);
/** Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Evaluation
* \{ */
bool DEG_is_evaluating(const Depsgraph *depsgraph);
bool DEG_is_active(const Depsgraph *depsgraph);
void DEG_make_active(Depsgraph *depsgraph);
void DEG_make_inactive(Depsgraph *depsgraph);
/* Returns the number of times the graph has been evaluated. */
uint64_t DEG_get_update_count(const Depsgraph *depsgraph);
/**
* Disable the visibility optimization making it so IDs which affect hidden objects or disabled
* modifiers are still evaluated.
*
* For example, this ensures that an object which is needed by a modifier is ignoring checks about
* whether the object is hidden or the modifier is disabled. */
void DEG_disable_visibility_optimization(Depsgraph *depsgraph);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Evaluation Debug
* \{ */
void DEG_debug_print_begin(Depsgraph *depsgraph);
void DEG_debug_print_eval(Depsgraph *depsgraph,
const char *function_name,
const char *object_name,
const void *object_address);
void DEG_debug_print_eval_subdata(Depsgraph *depsgraph,
const char *function_name,
const char *object_name,
const void *object_address,
const char *subdata_comment,
const char *subdata_name,
const void *subdata_address);
void DEG_debug_print_eval_subdata_index(Depsgraph *depsgraph,
const char *function_name,
const char *object_name,
const void *object_address,
const char *subdata_comment,
const char *subdata_name,
const void *subdata_address,
int subdata_index);
void DEG_debug_print_eval_parent_typed(Depsgraph *depsgraph,
const char *function_name,
const char *object_name,
const void *object_address,
const char *parent_comment,
const char *parent_name,
const void *parent_address);
void DEG_debug_print_eval_time(Depsgraph *depsgraph,
const char *function_name,
const char *object_name,
const void *object_address,
float time);
/** \} */