Refactor: change light linking object storage be dynamically allocated #108090

Closed
Brecht Van Lommel wants to merge 128 commits from light-linking-dna into cycles-light-linking

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
13 changed files with 179 additions and 97 deletions
Showing only changes of commit e1d9e127c2 - Show all commits

View File

@ -3,6 +3,8 @@
#include "blender/light_linking.h"
#include "scene/object.h"
#include "DNA_object_types.h"
CCL_NAMESPACE_BEGIN
@ -12,7 +14,7 @@ static const ::Object *get_blender_object(const BL::Object &object)
return reinterpret_cast<::Object *>(object.ptr.data);
}
static const ::LightLinking &get_light_linking(const BL::Object &object)
static const ::LightLinking *get_light_linking(const BL::Object &object)
{
const ::Object *blender_object = get_blender_object(object);
return blender_object->light_linking;
@ -21,41 +23,41 @@ static const ::LightLinking &get_light_linking(const BL::Object &object)
uint64_t BlenderLightLink::get_light_set_membership(const BL::Object & /*parent*/,
const BL::Object &object)
{
const ::LightLinking &light_linking = get_light_linking(object);
return light_linking.runtime.light_set_membership;
const ::LightLinking *light_linking = get_light_linking(object);
return (light_linking) ? light_linking->runtime.light_set_membership : LIGHT_LINK_MASK_ALL;
}
uint BlenderLightLink::get_receiver_light_set(const BL::Object &parent, const BL::Object &object)
{
if (parent) {
const ::LightLinking &parent_light_linking = get_light_linking(parent);
if (parent_light_linking.runtime.receiver_light_set) {
return parent_light_linking.runtime.receiver_light_set;
const ::LightLinking *parent_light_linking = get_light_linking(parent);
if (parent_light_linking && parent_light_linking->runtime.receiver_light_set) {
return parent_light_linking->runtime.receiver_light_set;
}
}
const ::LightLinking &light_linking = get_light_linking(object);
return light_linking.runtime.receiver_light_set;
const ::LightLinking *light_linking = get_light_linking(object);
return (light_linking) ? light_linking->runtime.receiver_light_set : 0;
}
uint64_t BlenderLightLink::get_shadow_set_membership(const BL::Object & /*parent*/,
const BL::Object &object)
{
const ::LightLinking &light_linking = get_light_linking(object);
return light_linking.runtime.shadow_set_membership;
const ::LightLinking *light_linking = get_light_linking(object);
return (light_linking) ? light_linking->runtime.shadow_set_membership : LIGHT_LINK_MASK_ALL;
}
uint BlenderLightLink::get_blocker_shadow_set(const BL::Object &parent, const BL::Object &object)
{
if (parent) {
const ::LightLinking &parent_light_linking = get_light_linking(parent);
if (parent_light_linking.runtime.blocker_shadow_set) {
return parent_light_linking.runtime.blocker_shadow_set;
const ::LightLinking *parent_light_linking = get_light_linking(parent);
if (parent_light_linking && parent_light_linking->runtime.blocker_shadow_set) {
return parent_light_linking->runtime.blocker_shadow_set;
}
}
const ::LightLinking &light_linking = get_light_linking(object);
return light_linking.runtime.blocker_shadow_set;
const ::LightLinking *light_linking = get_light_linking(object);
return (light_linking) ? light_linking->runtime.blocker_shadow_set : 0;
}
CCL_NAMESPACE_END

View File

@ -138,8 +138,8 @@ NODE_DEFINE(Light)
SOCKET_NODE(shader, "Shader", Shader::get_node_type());
SOCKET_STRING(lightgroup, "Light Group", ustring());
SOCKET_UINT64(light_set_membership, "Light Set Membership", 0);
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", 0);
SOCKET_UINT64(light_set_membership, "Light Set Membership", LIGHT_LINK_MASK_ALL);
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", LIGHT_LINK_MASK_ALL);
SOCKET_BOOLEAN(normalize, "Normalize", true);

View File

@ -101,9 +101,9 @@ NODE_DEFINE(Object)
SOCKET_STRING(lightgroup, "Light Group", ustring());
SOCKET_UINT(receiver_light_set, "Light Set Index", 0);
SOCKET_UINT64(light_set_membership, "Light Set Membership", 0);
SOCKET_UINT64(light_set_membership, "Light Set Membership", LIGHT_LINK_MASK_ALL);
SOCKET_UINT(blocker_shadow_set, "Shadow Set Index", 0);
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", 0);
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", LIGHT_LINK_MASK_ALL);
return type;
}

View File

@ -28,10 +28,8 @@ typedef enum LightLinkingType {
LIGHT_LINKING_BLOCKER,
} LightLinkingType;
/* Get pointer or a collection of the given light linking type i=if the given object. */
struct Collection **BKE_light_linking_collection_ptr_get(struct Object *object,
LightLinkingType link_type);
struct Collection *BKE_light_linking_collection_get(struct Object *object,
/* Get a collection of the given light linking type of the given object. */
struct Collection *BKE_light_linking_collection_get(const struct Object *object,
LightLinkingType link_type);
/* Create new collection and assign it as a light or shadow linking collection (denoted by the

View File

@ -5,6 +5,8 @@
#include <string>
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
@ -23,30 +25,21 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
Collection **BKE_light_linking_collection_ptr_get(Object *object, const LightLinkingType link_type)
Collection *BKE_light_linking_collection_get(const Object *object,
const LightLinkingType link_type)
{
LightLinking &light_linking = object->light_linking;
switch (link_type) {
case LIGHT_LINKING_RECEIVER:
return &light_linking.receiver_collection;
case LIGHT_LINKING_BLOCKER:
return &light_linking.blocker_collection;
}
BLI_assert_unreachable();
return nullptr;
}
Collection *BKE_light_linking_collection_get(Object *object, const LightLinkingType link_type)
{
Collection **collection_ptr = BKE_light_linking_collection_ptr_get(object, link_type);
if (!collection_ptr) {
BLI_assert_unreachable();
if (!object->light_linking) {
return nullptr;
}
return *collection_ptr;
switch (link_type) {
case LIGHT_LINKING_RECEIVER:
return object->light_linking->receiver_collection;
case LIGHT_LINKING_BLOCKER:
return object->light_linking->blocker_collection;
}
return nullptr;
}
static std::string get_default_collection_name(const Object *object,
@ -86,17 +79,41 @@ void BKE_light_linking_collection_assign_only(struct Object *object,
struct Collection *new_collection,
const LightLinkingType link_type)
{
Collection **collection_ptr = BKE_light_linking_collection_ptr_get(object, link_type);
/* Unassign old collection if any, */
if (*collection_ptr) {
id_us_min(&(*collection_ptr)->id);
/* Remove user from old collection. */
Collection *old_collection = BKE_light_linking_collection_get(object, link_type);
if (old_collection) {
id_us_min(&old_collection->id);
}
*collection_ptr = new_collection;
/* Allocate light linking on demand. */
if (new_collection && !object->light_linking) {
object->light_linking = MEM_cnew<LightLinking>(__func__);
}
if (new_collection) {
id_us_plus(&new_collection->id);
if (object->light_linking) {
/* Assign and increment user of new collection. */
switch (link_type) {
case LIGHT_LINKING_RECEIVER:
object->light_linking->receiver_collection = new_collection;
break;
case LIGHT_LINKING_BLOCKER:
object->light_linking->blocker_collection = new_collection;
break;
default:
BLI_assert_unreachable();
break;
}
if (new_collection) {
id_us_plus(&new_collection->id);
}
/* Free if empty. */
if (object->light_linking->receiver_collection == nullptr &&
object->light_linking->blocker_collection == nullptr)
{
MEM_SAFE_FREE(object->light_linking);
}
}
}
@ -136,8 +153,8 @@ static CollectionLightLinking *light_linking_collection_add_object(Main *bmain,
/* Add child collection to the light linking collection and return corresponding
* CollectionLightLinking settings.
*
* If the child collection is already in the collection then the content of the collection is not
* modified, and the existing light linking settings are returned. */
* If the child collection is already in the collection then the content of the collection is
* not modified, and the existing light linking settings are returned. */
static CollectionLightLinking *light_linking_collection_add_collection(Main *bmain,
Collection *collection,
Collection *child)

View File

@ -267,6 +267,9 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
if (ob_src->lightgroup) {
ob_dst->lightgroup = (LightgroupMembership *)MEM_dupallocN(ob_src->lightgroup);
}
if (ob_src->light_linking) {
ob_dst->light_linking = (LightLinking *)MEM_dupallocN(ob_src->light_linking);
}
if ((flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) != 0) {
if (ob_src->lightprobe_cache) {
@ -331,6 +334,7 @@ static void object_free_data(ID *id)
BKE_previewimg_free(&ob->preview);
MEM_SAFE_FREE(ob->lightgroup);
MEM_SAFE_FREE(ob->light_linking);
BKE_lightprobe_cache_free(ob);
}
@ -470,10 +474,12 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, object->light_linking.receiver_collection, IDWALK_CB_USER);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, object->light_linking.blocker_collection, IDWALK_CB_USER);
if (object->light_linking) {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, object->light_linking->receiver_collection, IDWALK_CB_USER);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, object->light_linking->blocker_collection, IDWALK_CB_USER);
}
}
static void object_foreach_path_pointcache(ListBase *ptcache_list,
@ -616,6 +622,9 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
if (ob->lightgroup) {
BLO_write_struct(writer, LightgroupMembership, ob->lightgroup);
}
if (ob->light_linking) {
BLO_write_struct(writer, LightgroupMembership, ob->light_linking);
}
if (ob->lightprobe_cache) {
BLO_write_struct(writer, LightProbeObjectCache, ob->lightprobe_cache);
@ -839,6 +848,7 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
BKE_previewimg_blend_read(reader, ob->preview);
BLO_read_data_address(reader, &ob->lightgroup);
BLO_read_data_address(reader, &ob->light_linking);
BLO_read_data_address(reader, &ob->lightprobe_cache);
if (ob->lightprobe_cache) {
@ -1040,8 +1050,10 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
BLO_read_id_address(reader, id, &ob->rigidbody_constraint->ob2);
}
BLO_read_id_address(reader, id, &ob->light_linking.receiver_collection);
BLO_read_id_address(reader, id, &ob->light_linking.blocker_collection);
if (ob->light_linking) {
BLO_read_id_address(reader, id, &ob->light_linking->receiver_collection);
BLO_read_id_address(reader, id, &ob->light_linking->blocker_collection);
}
}
/* XXX deprecated - old animation system */
@ -1160,8 +1172,10 @@ static void object_blend_read_expand(BlendExpander *expander, ID *id)
}
/* Light and shadow linking. */
BLO_expand(expander, ob->light_linking.receiver_collection);
BLO_expand(expander, ob->light_linking.blocker_collection);
if (ob->light_linking) {
BLO_expand(expander, ob->light_linking->receiver_collection);
BLO_expand(expander, ob->light_linking->blocker_collection);
}
}
static void object_lib_override_apply_post(ID *id_dst, ID *id_src)

View File

@ -1136,8 +1136,10 @@ void DepsgraphNodeBuilder::build_object_light_linking(Object *object)
graph_->light_linking_cache.add_emitter(*graph_->scene, *object);
build_light_linking_collection(object->light_linking.receiver_collection);
build_light_linking_collection(object->light_linking.blocker_collection);
if (object->light_linking) {
build_light_linking_collection(object->light_linking->receiver_collection);
build_light_linking_collection(object->light_linking->blocker_collection);
}
}
void DepsgraphNodeBuilder::build_light_linking_collection(Collection *collection)

View File

@ -1255,12 +1255,14 @@ void DepsgraphRelationBuilder::build_object_light_linking(Object *emitter)
const OperationKey light_linking_key(
&emitter->id, NodeType::SHADING, OperationCode::LIGHT_LINKING_UPDATE);
LightLinking &light_linking = emitter->light_linking;
add_relation(hierarchy_key, light_linking_key, "Light Linking From Layer");
build_light_linking_collection(emitter, light_linking.receiver_collection);
build_light_linking_collection(emitter, light_linking.blocker_collection);
if (emitter->light_linking) {
LightLinking &light_linking = *emitter->light_linking;
build_light_linking_collection(emitter, light_linking.receiver_collection);
build_light_linking_collection(emitter, light_linking.blocker_collection);
}
}
void DepsgraphRelationBuilder::build_light_linking_collection(Object *emitter,

View File

@ -381,7 +381,7 @@ void Cache::add_light_linking_emitter(const Scene &scene, const Object &emitter)
emitter);
if (light_emitter_data) {
foreach_light_collection_object(
*emitter.light_linking.receiver_collection,
*emitter.light_linking->receiver_collection,
[&](const CollectionLightLinking &collection_light_linking, const Object &receiver) {
add_receiver_object(*light_emitter_data, collection_light_linking, receiver);
});
@ -400,7 +400,7 @@ void Cache::add_shadow_linking_emitter(const Scene &scene, const Object &emitter
scene, emitter);
if (shadow_emitter_data) {
foreach_light_collection_object(
*emitter.light_linking.blocker_collection,
*emitter.light_linking->blocker_collection,
[&](const CollectionLightLinking &collection_light_linking, const Object &receiver) {
add_blocker_object(*shadow_emitter_data, collection_light_linking, receiver);
});
@ -448,20 +448,27 @@ void Cache::end_build(const Scene &scene)
/* Set runtime data in light linking. */
void Cache::eval_runtime_data(Object &object_eval) const
{
LightLinking &light_linking = object_eval.light_linking;
if (!has_light_linking()) {
/* No light linking used in the scene. */
/* No light linking used in the scene, still reset to default on objects that have
* allocated light linking data structures since we can't free them here. */
if (object_eval.light_linking) {
LightLinking &light_linking = *object_eval.light_linking;
light_linking.runtime.receiver_light_set = 0;
light_linking.runtime.light_set_membership = EmitterSetMembership::SET_MEMBERSHIP_ALL;
light_linking.runtime.receiver_light_set = 0;
light_linking.runtime.light_set_membership = EmitterSetMembership::SET_MEMBERSHIP_ALL;
light_linking.runtime.blocker_shadow_set = 0;
light_linking.runtime.shadow_set_membership = EmitterSetMembership::SET_MEMBERSHIP_ALL;
light_linking.runtime.blocker_shadow_set = 0;
light_linking.runtime.shadow_set_membership = EmitterSetMembership::SET_MEMBERSHIP_ALL;
}
return;
}
/* Allocate light linking on demand. */
brecht marked this conversation as resolved Outdated

It feels like there is still possibility to skip allocation here if the light and shadow sets are default, and there is no emitter data.
Can also happen later, once the ground work for the DNA changes is landed.

It feels like there is still possibility to skip allocation here if the light and shadow sets are default, and there is no emitter data. Can also happen later, once the ground work for the DNA changes is landed.
if (!object_eval.light_linking) {
object_eval.light_linking = MEM_cnew<LightLinking>(__func__);
}
LightLinking &light_linking = *object_eval.light_linking;
/* Receiver and blocker configuration. */
light_linking.runtime.receiver_light_set = light_linking_.get_light_set_for(object_eval);
light_linking.runtime.blocker_shadow_set = shadow_linking_.get_light_set_for(object_eval);

View File

@ -126,11 +126,7 @@ class EmitterDataMap {
/* TODO(sergey): Check whether template specialization is preferred here. */
inline const Collection *get_collection(const Object &emitter) const
{
if (link_type_ == LIGHT_LINKING_BLOCKER) {
return emitter.light_linking.blocker_collection;
}
return emitter.light_linking.receiver_collection;
return BKE_light_linking_collection_get(&emitter, link_type_);
}
LightLinkingType link_type_ = LIGHT_LINKING_RECEIVER;
@ -283,8 +279,9 @@ class Cache {
/* Check whether object can be linked to an emitter without causing feedback loop. */
inline bool can_link_to_emitter(const Object &object)
{
return object.light_linking.receiver_collection == nullptr &&
object.light_linking.blocker_collection == nullptr;
return object.light_linking == nullptr ||
(object.light_linking->receiver_collection == nullptr &&
object.light_linking->blocker_collection == nullptr);
}
} // namespace blender::deg::light_linking

View File

@ -29,7 +29,12 @@ void ObjectRuntimeBackup::init_from_object(Object *object)
{
/* Store evaluated mesh and curve_cache, and make sure we don't free it. */
runtime = object->runtime;
light_linking_runtime = object->light_linking.runtime;
if (object->light_linking) {
light_linking_runtime = object->light_linking->runtime;
}
else {
memset(&light_linking_runtime, 0, sizeof(light_linking_runtime));
}
BKE_object_runtime_reset(object);
/* Keep bbox (for now at least). */
object->runtime.bb = runtime.bb;
@ -123,7 +128,9 @@ void ObjectRuntimeBackup::restore_to_object(Object *object)
}
}
object->light_linking.runtime = light_linking_runtime;
if (object->light_linking) {
object->light_linking->runtime = light_linking_runtime;
}
object->base_flag = base_flag;
object->base_local_view_bits = base_local_view_bits;

View File

@ -506,13 +506,12 @@ typedef struct Object {
/** Lightgroup membership information. */
struct LightgroupMembership *lightgroup;
LightLinking light_linking;
/** Light linking information. */
LightLinking *light_linking;
/** Irradiance caches baked for this object (light-probes only). */
struct LightProbeObjectCache *lightprobe_cache;
void *_pad9;
/** Runtime evaluation data (keep last). */
Object_Runtime runtime;
} Object;

View File

@ -2357,6 +2357,25 @@ void rna_Object_lightgroup_set(PointerRNA *ptr, const char *value)
BKE_lightgroup_membership_set(&((Object *)ptr->owner_id)->lightgroup, value);
}
static PointerRNA rna_Object_light_linking_get(PointerRNA *ptr)
{
return rna_pointer_inherit_refine(ptr, &RNA_ObjectLightLinking, ptr->data);
}
static char *rna_ObjectLightLinking_path(const PointerRNA *UNUSED(ptr))
{
return BLI_strdup("light_linking");
}
static PointerRNA rna_LightLinking_receiver_collection_get(PointerRNA *ptr)
{
Object *object = (Object *)ptr->owner_id;
PointerRNA collection_ptr;
RNA_id_pointer_create((ID *)BKE_light_linking_collection_get(object, LIGHT_LINKING_RECEIVER),
&collection_ptr);
return collection_ptr;
}
static void rna_LightLinking_receiver_collection_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *UNUSED(reports))
@ -2367,6 +2386,15 @@ static void rna_LightLinking_receiver_collection_set(PointerRNA *ptr,
BKE_light_linking_collection_assign_only(object, new_collection, LIGHT_LINKING_RECEIVER);
}
static PointerRNA rna_LightLinking_blocker_collection_get(PointerRNA *ptr)
{
Object *object = (Object *)ptr->owner_id;
PointerRNA collection_ptr;
RNA_id_pointer_create((ID *)BKE_light_linking_collection_get(object, LIGHT_LINKING_BLOCKER),
&collection_ptr);
return collection_ptr;
}
static void rna_LightLinking_blocker_collection_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *UNUSED(reports))
@ -3923,7 +3951,8 @@ static void rna_def_object(BlenderRNA *brna)
/* Light Linking. */
prop = RNA_def_property(srna, "light_linking", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "LightLinking");
RNA_def_property_struct_type(prop, "ObjectLightLinking");
RNA_def_property_pointer_funcs(prop, "rna_Object_light_linking_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Light Linking", "Light linking settings");
RNA_define_lib_overridable(false);
@ -3942,15 +3971,20 @@ static void rna_def_object_light_linking(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "LightLinking", NULL);
RNA_def_struct_sdna(srna, "LightLinking");
RNA_def_struct_ui_text(srna, "Light Linking", "");
srna = RNA_def_struct(brna, "ObjectLightLinking", NULL);
RNA_def_struct_ui_text(srna, "Object Light Linking", "");
RNA_def_struct_sdna(srna, "Object");
RNA_def_struct_nested(brna, srna, "Object");
RNA_def_struct_path_func(srna, "rna_ObjectLightLinking_path");
prop = RNA_def_property(srna, "receiver_collection", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(
prop, NULL, "rna_LightLinking_receiver_collection_set", NULL, NULL);
RNA_def_property_pointer_funcs(prop,
"rna_LightLinking_receiver_collection_get",
"rna_LightLinking_receiver_collection_set",
NULL,
NULL);
RNA_def_property_ui_text(prop,
"Receiver Collection",
"Collection which defines light linking relation of this emitter");
@ -3959,8 +3993,11 @@ static void rna_def_object_light_linking(BlenderRNA *brna)
prop = RNA_def_property(srna, "blocker_collection", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(
prop, NULL, "rna_LightLinking_blocker_collection_set", NULL, NULL);
RNA_def_property_pointer_funcs(prop,
"rna_LightLinking_blocker_collection_get",
"rna_LightLinking_blocker_collection_set",
NULL,
NULL);
RNA_def_property_ui_text(prop,
"Blocker Collection",
"Collection which defines objects which block light from this emitter");