Merge branch 'master' into blender2.8
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 13 Dec 2017 14:07:42 +0000 (15:07 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 13 Dec 2017 14:07:42 +0000 (15:07 +0100)
1  2 
source/blender/blenkernel/intern/mask.c
source/blender/blenloader/intern/readfile.c
source/blender/depsgraph/intern/depsgraph_tag.cc

index eaa2f89ab8248a06bac4bbf58532cd8c8a8bdb6f,cd697cadc0e0acf3243b98a8f6505e60ffc23d35..92dee5b55d48876719c37f9bddaf44e1d181f5e2
@@@ -51,6 -51,7 +51,6 @@@
  
  #include "BKE_animsys.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_global.h"
  #include "BKE_library.h"
  #include "BKE_main.h"
@@@ -61,8 -62,6 +61,8 @@@
  #include "BKE_movieclip.h"
  #include "BKE_image.h"
  
 +#include "DEG_depsgraph_build.h"
 +
  static struct {
        ListBase splines;
        struct GHash *id_hash;
@@@ -819,7 -818,7 +819,7 @@@ Mask *BKE_mask_new(Main *bmain, const c
        mask->sfra = 1;
        mask->efra = 100;
  
 -      DAG_relations_tag_update(bmain);
 +      DEG_relations_tag_update(bmain);
  
        return mask;
  }
@@@ -1464,7 -1463,7 +1464,7 @@@ void BKE_mask_update_scene(Main *bmain
        Mask *mask;
  
        for (mask = bmain->mask.first; mask; mask = mask->id.next) {
-               if (mask->id.tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) {
+               if (mask->id.tag & LIB_TAG_ID_RECALC_ALL) {
                        bool do_new_frame = (mask->id.tag & LIB_TAG_ID_RECALC_DATA) != 0;
                        BKE_mask_evaluate_all_masks(bmain, CFRA, do_new_frame);
                }
index 6df5a5057883366363fddbc1796f52e395f41d10,b6543fc8662e3bb79ee0236e700d257395fb0e38..494c1d5110b62ee85ab96a0269fa2c9e44ca66bf
  
  /* allow readfile to use deprecated functionality */
  #define DNA_DEPRECATED_ALLOW
 +/* Allow using DNA struct members that are marked as private for read/write.
 + * Note: Each header that uses this needs to define its own way of handling
 + * it. There's no generic implementation, direct use does nothing. */
 +#define DNA_PRIVATE_READ_WRITE_ALLOW
  
  #include "DNA_anim_types.h"
  #include "DNA_armature_types.h"
@@@ -76,7 -72,6 +76,7 @@@
  #include "DNA_ipo_types.h"
  #include "DNA_key_types.h"
  #include "DNA_lattice_types.h"
 +#include "DNA_layer_types.h"
  #include "DNA_lamp_types.h"
  #include "DNA_linestyle_types.h"
  #include "DNA_meta_types.h"
@@@ -89,7 -84,6 +89,7 @@@
  #include "DNA_object_types.h"
  #include "DNA_packedFile_types.h"
  #include "DNA_particle_types.h"
 +#include "DNA_lightprobe_types.h"
  #include "DNA_property_types.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_text_types.h"
  #include "DNA_sound_types.h"
  #include "DNA_space_types.h"
  #include "DNA_vfont_types.h"
 +#include "DNA_workspace_types.h"
  #include "DNA_world_types.h"
  #include "DNA_movieclip_types.h"
  #include "DNA_mask_types.h"
  
 +#include "RNA_access.h"
 +
  #include "MEM_guardedalloc.h"
  
  #include "BLI_endian_switch.h"
  #include "BKE_constraint.h"
  #include "BKE_context.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_effect.h"
  #include "BKE_fcurve.h"
  #include "BKE_global.h" // for G
  #include "BKE_group.h"
 +#include "BKE_layer.h"
  #include "BKE_library.h" // for which_libbase
  #include "BKE_library_idmap.h"
 +#include "BKE_library_override.h"
  #include "BKE_library_query.h"
  #include "BKE_idcode.h"
  #include "BKE_idprop.h"
  #include "BKE_outliner_treehash.h"
  #include "BKE_sound.h"
  #include "BKE_colortools.h"
 +#include "BKE_workspace.h"
 +
 +#include "DEG_depsgraph.h"
  
  #include "NOD_common.h"
  #include "NOD_socket.h"
@@@ -251,11 -238,9 +251,11 @@@ typedef struct OldNewMap 
  /* local prototypes */
  static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
  static void direct_link_modifiers(FileData *fd, ListBase *lb);
 -static void convert_tface_mt(FileData *fd, Main *main);
  static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
  static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
 +static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc);
 +static SceneCollection *get_scene_collection_active_or_create(
 +        struct Scene *scene, struct ViewLayer *view_layer, const int flag);
  
  /* this function ensures that reports are printed,
   * in the case of libraray linking errors this is important!
@@@ -2217,42 -2202,6 +2217,42 @@@ static PreviewImage *direct_link_previe
  
  /* ************ READ ID *************** */
  
 +static void lib_link_id(FileData *fd, Main *main)
 +{
 +      ListBase *lbarray[MAX_LIBARRAY];
 +      int base_count, i;
 +
 +      base_count = set_listbasepointers(main, lbarray);
 +
 +      for (i = 0; i < base_count; i++) {
 +              ListBase *lb = lbarray[i];
 +              ID *id;
 +
 +              for (id = lb->first; id; id = id->next) {
 +                      if (id->override_static) {
 +                              id->override_static->reference = newlibadr_us(fd, id->lib, id->override_static->reference);
 +                              id->override_static->storage = newlibadr_us(fd, id->lib, id->override_static->storage);
 +                      }
 +              }
 +      }
 +}
 +
 +static void direct_link_id_override_property_operation_cb(FileData *fd, void *data)
 +{
 +      IDOverrideStaticPropertyOperation *opop = data;
 +
 +      opop->subitem_reference_name = newdataadr(fd, opop->subitem_reference_name);
 +      opop->subitem_local_name = newdataadr(fd, opop->subitem_local_name);
 +}
 +
 +static void direct_link_id_override_property_cb(FileData *fd, void *data)
 +{
 +      IDOverrideStaticProperty *op = data;
 +
 +      op->rna_path = newdataadr(fd, op->rna_path);
 +      link_list_ex(fd, &op->operations, direct_link_id_override_property_operation_cb);
 +}
 +
  static void direct_link_id(FileData *fd, ID *id)
  {
        /*link direct data of ID properties*/
                IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
        }
        id->py_instance = NULL;
 +
 +      /* Link direct data of overrides. */
 +      if (id->override_static) {
 +              id->override_static = newdataadr(fd, id->override_static);
 +              link_list_ex(fd, &id->override_static->properties, direct_link_id_override_property_cb);
 +      }
  }
  
  /* ************ READ CurveMapping *************** */
@@@ -2831,89 -2774,6 +2831,89 @@@ static void direct_link_cachefile(FileD
        direct_link_animdata(fd, cache_file->adt);
  }
  
 +/* ************ READ WORKSPACES *************** */
 +
 +static void lib_link_workspaces(FileData *fd, Main *bmain)
 +{
 +      for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
 +              ListBase *layouts = BKE_workspace_layouts_get(workspace);
 +              ID *id = (ID *)workspace;
 +
 +              if ((id->tag & LIB_TAG_NEED_LINK) == 0) {
 +                      continue;
 +              }
 +              IDP_LibLinkProperty(id->properties, fd);
 +              id_us_ensure_real(id);
 +
 +              for (WorkSpaceDataRelation *relation = workspace->scene_viewlayer_relations.first;
 +                   relation != NULL;
 +                   relation = relation->next)
 +              {
 +                      relation->parent = newlibadr(fd, id->lib, relation->parent);
 +                      /* relation->value is set in direct_link_workspace_link_scene_data */
 +              }
 +
 +              for (WorkSpaceLayout *layout = layouts->first, *layout_next; layout; layout = layout_next) {
 +                      bScreen *screen = newlibadr(fd, id->lib, BKE_workspace_layout_screen_get(layout));
 +
 +                      layout_next = layout->next;
 +                      if (screen) {
 +                              BKE_workspace_layout_screen_set(layout, screen);
 +
 +                              if (ID_IS_LINKED(id)) {
 +                                      screen->winid = 0;
 +                                      if (screen->temp) {
 +                                              /* delete temp layouts when appending */
 +                                              BKE_workspace_layout_remove(bmain, workspace, layout);
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              id->tag &= ~LIB_TAG_NEED_LINK;
 +      }
 +}
 +
 +static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main *main)
 +{
 +      link_list(fd, BKE_workspace_layouts_get(workspace));
 +      link_list(fd, &workspace->hook_layout_relations);
 +      link_list(fd, &workspace->scene_viewlayer_relations);
 +      link_list(fd, BKE_workspace_transform_orientations_get(workspace));
 +
 +      for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first;
 +           relation;
 +           relation = relation->next)
 +      {
 +              relation->parent = newglobadr(fd, relation->parent); /* data from window - need to access through global oldnew-map */
 +              relation->value = newdataadr(fd, relation->value);
 +      }
 +
 +      if (ID_IS_LINKED(&workspace->id)) {
 +              /* Appending workspace so render layer is likely from a different scene. Unset
 +               * now, when activating workspace later we set a valid one from current scene. */
 +              BKE_workspace_relations_free(&workspace->scene_viewlayer_relations);
 +      }
 +
 +      /* Same issue/fix as in direct_link_workspace_link_scene_data: Can't read workspace data
 +       * when reading windows, so have to update windows after/when reading workspaces. */
 +      for (wmWindowManager *wm = main->wm.first; wm; wm = wm->id.next) {
 +              for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +                      WorkSpaceLayout *act_layout = newdataadr(fd, BKE_workspace_active_layout_get(win->workspace_hook));
 +                      if (act_layout) {
 +                              BKE_workspace_active_layout_set(win->workspace_hook, act_layout);
 +                      }
 +              }
 +      }
 +}
 +
 +static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id)
 +{
 +      WorkSpace *workspace = BKE_workspace_active_get(hook);
 +      BKE_workspace_active_set(hook, newlibadr(fd, id->lib, workspace));
 +}
 +
 +
  /* ************ READ MOTION PATHS *************** */
  
  /* direct data for cache */
@@@ -3217,7 -3077,7 +3217,7 @@@ static void direct_link_nodetree(FileDa
        ntree->adt = newdataadr(fd, ntree->adt);
        direct_link_animdata(fd, ntree->adt);
        
-       ntree->id.tag &= ~(LIB_TAG_ID_RECALC|LIB_TAG_ID_RECALC_DATA);
+       ntree->id.tag &= ~LIB_TAG_ID_RECALC_ALL;
  
        link_list(fd, &ntree->nodes);
        for (node = ntree->nodes.first; node; node = node->next) {
@@@ -3481,7 -3341,7 +3481,7 @@@ static void lib_link_pose(FileData *fd
        
  
        if (rebuild) {
 -              DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 +              DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                BKE_pose_tag_recalc(bmain, pose);
        }
  }
@@@ -3559,11 -3419,6 +3559,11 @@@ static void lib_link_camera(FileData *f
  
                        ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob);
                        
 +                      for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) {
 +                              bgpic->ima = newlibadr_us(fd, ca->id.lib, bgpic->ima);
 +                              bgpic->clip = newlibadr_us(fd, ca->id.lib, bgpic->clip);
 +                      }
 +
                        ca->id.tag &= ~LIB_TAG_NEED_LINK;
                }
        }
@@@ -3573,12 -3428,6 +3573,12 @@@ static void direct_link_camera(FileDat
  {
        ca->adt = newdataadr(fd, ca->adt);
        direct_link_animdata(fd, ca->adt);
 +
 +      link_list(fd, &ca->bg_images);
 +
 +      for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) {
 +              bgpic->iuser.ok = 1;
 +      }
  }
  
  
@@@ -3746,7 -3595,6 +3746,7 @@@ static void direct_link_mball(FileData 
        mb->editelems = NULL;
  /*    mb->edit_elems.first= mb->edit_elems.last= NULL;*/
        mb->lastelem = NULL;
 +      mb->batch_cache = NULL;
  }
  
  /* ************ READ WORLD ***************** */
@@@ -4016,7 -3864,6 +4016,7 @@@ static void direct_link_curve(FileData 
  
        cu->editnurb = NULL;
        cu->editfont = NULL;
 +      cu->batch_cache = NULL;
        
        for (nu = cu->nurb.first; nu; nu = nu->next) {
                nu->bezt = newdataadr(fd, nu->bezt);
@@@ -4523,14 -4370,55 +4523,14 @@@ static void direct_link_particlesystems
  
                psys->tree = NULL;
                psys->bvhtree = NULL;
 +
 +              psys->batch_cache = NULL;
        }
        return;
  }
  
  /* ************ READ MESH ***************** */
  
 -static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
 -{
 -      MTFace *tf= mtface;
 -      int i;
 -      
 -      /* Add pseudo-references (not fake users!) to images used by texface. A
 -       * little bogus; it would be better if each mesh consistently added one ref
 -       * to each image it used. - z0r */
 -      for (i = 0; i < totface; i++, tf++) {
 -              tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage);
 -      }
 -}
 -
 -static void lib_link_customdata_mtface(FileData *fd, Mesh *me, CustomData *fdata, int totface)
 -{
 -      int i;
 -      for (i = 0; i < fdata->totlayer; i++) {
 -              CustomDataLayer *layer = &fdata->layers[i];
 -              
 -              if (layer->type == CD_MTFACE)
 -                      lib_link_mtface(fd, me, layer->data, totface);
 -      }
 -
 -}
 -
 -static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata, int totface)
 -{
 -      int i;
 -
 -      for (i=0; i < pdata->totlayer; i++) {
 -              CustomDataLayer *layer = &pdata->layers[i];
 -              
 -              if (layer->type == CD_MTEXPOLY) {
 -                      MTexPoly *tf= layer->data;
 -                      int j;
 -                      
 -                      for (j = 0; j < totface; j++, tf++) {
 -                              tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage);
 -                      }
 -              }
 -      }
 -}
 -
  static void lib_link_mesh(FileData *fd, Main *main)
  {
        Mesh *me;
                        me->ipo = newlibadr_us(fd, me->id.lib, me->ipo); // XXX: deprecated: old anim sys
                        me->key = newlibadr_us(fd, me->id.lib, me->key);
                        me->texcomesh = newlibadr_us(fd, me->id.lib, me->texcomesh);
 -                      
 -                      lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
 -                      lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly);
 -                      if (me->mr && me->mr->levels.first) {
 -                              lib_link_customdata_mtface(fd, me, &me->mr->fdata,
 -                                                         ((MultiresLevel*)me->mr->levels.first)->totface);
 -                      }
                }
        }
  
 -      /* convert texface options to material */
 -      convert_tface_mt(fd, main);
 -
        for (me = main->mesh.first; me; me = me->id.next) {
                if (me->id.tag & LIB_TAG_NEED_LINK) {
                        /*check if we need to convert mfaces to mpolys*/
@@@ -4715,6 -4613,7 +4715,6 @@@ static void direct_link_mesh(FileData *
        mesh->dvert = newdataadr(fd, mesh->dvert);
        mesh->mloopcol = newdataadr(fd, mesh->mloopcol);
        mesh->mloopuv = newdataadr(fd, mesh->mloopuv);
 -      mesh->mtpoly = newdataadr(fd, mesh->mtpoly);
        mesh->mselect = newdataadr(fd, mesh->mselect);
        
        /* animdata */
  
        mesh->bb = NULL;
        mesh->edit_btmesh = NULL;
 +      mesh->batch_cache = NULL;
        
        /* happens with old files */
        if (mesh->mselect == NULL) {
                mesh->totselect = 0;
        }
  
 -      if (mesh->mloopuv || mesh->mtpoly) {
 -              /* for now we have to ensure texpoly and mloopuv layers are aligned
 -               * in the future we may allow non-aligned layers */
 -              BKE_mesh_cd_validate(mesh);
 -      }
 -
        /* Multires data */
        mesh->mr= newdataadr(fd, mesh->mr);
        if (mesh->mr) {
@@@ -4819,7 -4723,6 +4819,7 @@@ static void direct_link_latt(FileData *
        direct_link_dverts(fd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert);
        
        lt->editlatt = NULL;
 +      lt->batch_cache = NULL;
        
        lt->adt = newdataadr(fd, lt->adt);
        direct_link_animdata(fd, lt->adt);
@@@ -4862,15 -4765,7 +4862,15 @@@ static void lib_link_object(FileData *f
                        ob->parent = newlibadr(fd, ob->id.lib, ob->parent);
                        ob->track = newlibadr(fd, ob->id.lib, ob->track);
                        ob->poselib = newlibadr_us(fd, ob->id.lib, ob->poselib);
 -                      ob->dup_group = newlibadr_us(fd, ob->id.lib, ob->dup_group);
 +
 +                      /* 2.8x drops support for non-empty dupli instances. */
 +                      if (ob->type == OB_EMPTY) {
 +                              ob->dup_group = newlibadr_us(fd, ob->id.lib, ob->dup_group);
 +                      }
 +                      else {
 +                              ob->dup_group = NULL;
 +                              ob->transflag &= ~OB_DUPLIGROUP;
 +                      }
                        
                        ob->proxy = newlibadr_us(fd, ob->id.lib, ob->proxy);
                        if (ob->proxy) {
@@@ -5176,8 -5071,6 +5176,8 @@@ static void direct_link_pose(FileData *
                
                /* in case this value changes in future, clamp else we get undefined behavior */
                CLAMP(pchan->rotmode, ROT_MODE_MIN, ROT_MODE_MAX);
 +
 +              pchan->draw_data = NULL;
        }
        pose->ikdata = NULL;
        if (pose->ikparam != NULL) {
@@@ -5520,6 -5413,11 +5520,6 @@@ static void direct_link_object(FileDat
        /* weak weak... this was only meant as draw flag, now is used in give_base_to_objects too */
        ob->flag &= ~OB_FROMGROUP;
  
 -      /* This is a transient flag; clear in order to avoid unneeded object update pending from
 -       * time when file was saved.
 -       */
 -      ob->recalc = 0;
 -
        /* XXX This should not be needed - but seems like it can happen in some cases, so for now play safe... */
        ob->proxy_from = NULL;
  
                direct_link_motionpath(fd, ob->mpath);
        
        link_list(fd, &ob->defbase);
 +      link_list(fd, &ob->fmaps);
  // XXX deprecated - old animation system <<<
        direct_link_nlastrips(fd, &ob->nlastrips);
        link_list(fd, &ob->constraintChannels);
        ob->derivedDeform = NULL;
        ob->derivedFinal = NULL;
        BLI_listbase_clear(&ob->gpulamp);
 +      BLI_listbase_clear(&ob->drawdata);
        link_list(fd, &ob->pc_ids);
  
        /* Runtime curve data  */
        ob->currentlod = ob->lodlevels.first;
  
        ob->preview = direct_link_preview_image(fd, ob->preview);
 +
 +      ob->base_collection_properties = NULL;
  }
  
  /* ************ READ SCENE ***************** */
@@@ -5817,45 -5711,6 +5817,45 @@@ static bool scene_validate_setscene__li
  }
  #endif
  
 +static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollection *sc)
 +{
 +      for (LinkData *link = sc->objects.first; link; link = link->next) {
 +              link->data = newlibadr_us(fd, lib, link->data);
 +              BLI_assert(link->data);
 +      }
 +
 +      for (LinkData *link = sc->filter_objects.first; link; link = link->next) {
 +              link->data = newlibadr_us(fd, lib, link->data);
 +              BLI_assert(link->data);
 +      }
 +
 +      for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
 +              lib_link_scene_collection(fd, lib, nsc);
 +      }
 +}
 +
 +static void lib_link_view_layer(FileData *fd, Library *lib, ViewLayer *view_layer)
 +{
 +      /* tag scene layer to update for collection tree evaluation */
 +      view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY;
 +
 +      for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
 +              fmc->script = newlibadr(fd, lib, fmc->script);
 +      }
 +
 +      for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
 +              fls->linestyle = newlibadr_us(fd, lib, fls->linestyle);
 +              fls->group = newlibadr_us(fd, lib, fls->group);
 +      }
 +
 +      for (Base *base = view_layer->object_bases.first; base; base = base->next) {
 +              /* we only bump the use count for the collection objects */
 +              base->object = newlibadr(fd, lib, base->object);
 +              base->flag |= BASE_DIRTY_ENGINE_SETTINGS;
 +              base->collection_properties = NULL;
 +      }
 +}
 +
  static void lib_link_scene(FileData *fd, Main *main)
  {
  #ifdef USE_SETSCENE_CHECK
                        
                        sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object);
                        
 -                      for (Base *next, *base = sce->base.first; base; base = next) {
 -                              next = base->next;
 +                      for (Base *base_legacy_next, *base_legacy = sce->base.first; base_legacy; base_legacy = base_legacy_next) {
 +                              base_legacy_next = base_legacy->next;
                                
 -                              base->object = newlibadr_us(fd, sce->id.lib, base->object);
 +                              base_legacy->object = newlibadr_us(fd, sce->id.lib, base_legacy->object);
                                
 -                              if (base->object == NULL) {
 +                              if (base_legacy->object == NULL) {
                                        blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: object lost from scene: '%s'"),
                                                         sce->id.name + 2);
 -                                      BLI_remlink(&sce->base, base);
 -                                      if (base == sce->basact) sce->basact = NULL;
 -                                      MEM_freeN(base);
 +                                      BLI_remlink(&sce->base, base_legacy);
 +                                      if (base_legacy == sce->basact) sce->basact = NULL;
 +                                      MEM_freeN(base_legacy);
                                }
                        }
                        
                        
                        for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) {
                                srl->mat_override = newlibadr_us(fd, sce->id.lib, srl->mat_override);
 -                              srl->light_override = newlibadr_us(fd, sce->id.lib, srl->light_override);
                                for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
                                        fmc->script = newlibadr(fd, sce->id.lib, fmc->script);
                                }
                        /* Motion Tracking */
                        sce->clip = newlibadr_us(fd, sce->id.lib, sce->clip);
  
 +                      lib_link_scene_collection(fd, sce->id.lib, sce->collection);
 +
 +                      for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
 +                              lib_link_view_layer(fd, sce->id.lib, view_layer);
 +                      }
 +
  #ifdef USE_SETSCENE_CHECK
                        if (sce->set != NULL) {
                                /* link flag for scenes with set would be reset later,
@@@ -6110,107 -5960,18 +6110,107 @@@ static void direct_link_view_settings(F
                direct_link_curvemapping(fd, view_settings->curve_mapping);
  }
  
 -static void direct_link_scene(FileData *fd, Scene *sce)
 +static void direct_link_scene_collection(FileData *fd, SceneCollection *sc)
 +{
 +      link_list(fd, &sc->objects);
 +      link_list(fd, &sc->filter_objects);
 +      link_list(fd, &sc->scene_collections);
 +
 +      for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
 +              direct_link_scene_collection(fd, nsc);
 +      }
 +}
 +
 +static void direct_link_layer_collections(FileData *fd, ListBase *lb)
 +{
 +      link_list(fd, lb);
 +      for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
 +              lc->scene_collection = newdataadr(fd, lc->scene_collection);
 +
 +              link_list(fd, &lc->object_bases);
 +
 +              for (LinkData *link = lc->object_bases.first; link; link = link->next) {
 +                      link->data = newdataadr(fd, link->data);
 +              }
 +
 +              link_list(fd, &lc->overrides);
 +
 +              if (lc->properties) {
 +                      lc->properties = newdataadr(fd, lc->properties);
 +                      IDP_DirectLinkGroup_OrFree(&lc->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
 +                      BKE_layer_collection_engine_settings_validate_collection(lc);
 +              }
 +              lc->properties_evaluated = NULL;
 +
 +              direct_link_layer_collections(fd, &lc->layer_collections);
 +      }
 +}
 +
 +static void direct_link_view_layer(FileData *fd, ViewLayer *view_layer)
 +{
 +      view_layer->stats = NULL;
 +      link_list(fd, &view_layer->object_bases);
 +      view_layer->basact = newdataadr(fd, view_layer->basact);
 +      direct_link_layer_collections(fd, &view_layer->layer_collections);
 +
 +      if (view_layer->properties != NULL) {
 +              view_layer->properties = newdataadr(fd, view_layer->properties);
 +              BLI_assert(view_layer->properties != NULL);
 +              IDP_DirectLinkGroup_OrFree(&view_layer->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
 +              BKE_view_layer_engine_settings_validate_layer(view_layer);
 +      }
 +
 +      view_layer->id_properties = newdataadr(fd, view_layer->id_properties);
 +      IDP_DirectLinkGroup_OrFree(&view_layer->id_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
 +
 +      link_list(fd, &(view_layer->freestyle_config.modules));
 +      link_list(fd, &(view_layer->freestyle_config.linesets));
 +
 +      view_layer->properties_evaluated = NULL;
 +
 +      BLI_listbase_clear(&view_layer->drawdata);
 +}
 +
 +/**
 + * Workspaces store a render layer pointer which can only be read after scene is read.
 + */
 +static void direct_link_workspace_link_scene_data(
 +        FileData *fd, Scene *scene, const ListBase *workspaces)
 +{
 +      for (WorkSpace *workspace = workspaces->first; workspace; workspace = workspace->id.next) {
 +              for (WorkSpaceDataRelation *relation = workspace->scene_viewlayer_relations.first;
 +                   relation != NULL;
 +                   relation = relation->next)
 +              {
 +                      ViewLayer *layer = newdataadr(fd, relation->value);
 +                      if (layer) {
 +                              BLI_assert(BLI_findindex(&scene->view_layers, layer) != -1);
 +                              /* relation->parent is set in lib_link_workspaces */
 +                              relation->value = layer;
 +                      }
 +              }
 +
 +              if (workspace->view_layer) { /* this was temporariliy used during 2.8 project. Keep files compatible */
 +                      ViewLayer *layer = newdataadr(fd, workspace->view_layer);
 +                      /* only set when layer is from the scene we read */
 +                      if (layer && (BLI_findindex(&scene->view_layers, layer) != -1)) {
 +                              workspace->view_layer = layer;
 +                      }
 +              }
 +      }
 +}
 +
 +static void direct_link_scene(FileData *fd, Scene *sce, Main *bmain)
  {
        Editing *ed;
        Sequence *seq;
        MetaStack *ms;
        RigidBodyWorld *rbw;
 +      ViewLayer *view_layer;
        SceneRenderLayer *srl;
        
 -      sce->theDag = NULL;
 -      sce->depsgraph = NULL;
 +      sce->depsgraph_hash = NULL;
        sce->obedit = NULL;
 -      sce->stats = NULL;
        sce->fps_info = NULL;
        sce->customdata_mask_modal = 0;
        sce->lay_updated = 0;
                sce->toolsettings->imapaint.paintcursor = NULL;
                sce->toolsettings->particle.paintcursor = NULL;
                sce->toolsettings->particle.scene = NULL;
 +              sce->toolsettings->particle.view_layer = NULL;
                sce->toolsettings->particle.object = NULL;
                sce->toolsettings->gp_sculpt.paintcursor = NULL;
                
        }
        
        link_list(fd, &(sce->markers));
 -      link_list(fd, &(sce->transform_spaces));
 +      link_list(fd, &(sce->transform_spaces)); /* only for old files */
        link_list(fd, &(sce->r.layers));
        link_list(fd, &(sce->r.views));
  
        for (srl = sce->r.layers.first; srl; srl = srl->next) {
                srl->prop = newdataadr(fd, srl->prop);
                IDP_DirectLinkGroup_OrFree(&srl->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
 -      }
 -      for (srl = sce->r.layers.first; srl; srl = srl->next) {
                link_list(fd, &(srl->freestyleConfig.modules));
 -      }
 -      for (srl = sce->r.layers.first; srl; srl = srl->next) {
                link_list(fd, &(srl->freestyleConfig.linesets));
        }
        
        sce->preview = direct_link_preview_image(fd, sce->preview);
  
        direct_link_curvemapping(fd, &sce->r.mblur_shutter_curve);
 +
 +      /* this runs before the very first doversion */
 +      if (sce->collection) {
 +              sce->collection = newdataadr(fd, sce->collection);
 +              direct_link_scene_collection(fd, sce->collection);
 +      }
 +
 +      /* insert into global old-new map for reading without UI (link_global accesses it again) */
 +      link_glob_list(fd, &sce->view_layers);
 +      for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
 +              direct_link_view_layer(fd, view_layer);
 +      }
 +
 +      sce->collection_properties = newdataadr(fd, sce->collection_properties);
 +      IDP_DirectLinkGroup_OrFree(&sce->collection_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
 +
 +      sce->layer_properties = newdataadr(fd, sce->layer_properties);
 +      IDP_DirectLinkGroup_OrFree(&sce->layer_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
 +
 +      BKE_layer_collection_engine_settings_validate_scene(sce);
 +      BKE_view_layer_engine_settings_validate_scene(sce);
 +
 +      direct_link_workspace_link_scene_data(fd, sce, &bmain->workspaces);
  }
  
  /* ************ READ WM ***************** */
@@@ -6481,12 -6222,6 +6481,12 @@@ static void direct_link_windowmanager(F
        link_list(fd, &wm->windows);
        
        for (win = wm->windows.first; win; win = win->next) {
 +              WorkSpaceInstanceHook *hook = win->workspace_hook;
 +
 +              win->workspace_hook = newdataadr(fd, hook);
 +              /* we need to restore a pointer to this later when reading workspaces, so store in global oldnew-map */
 +              oldnewmap_insert(fd->globmap, hook, win->workspace_hook, 0);
 +
                win->ghostwin = NULL;
                win->eventstate = NULL;
                win->curswin = NULL;
        wm->addonconf = NULL;
        wm->userconf = NULL;
        
 +      wm->message_bus = NULL;
 +
        BLI_listbase_clear(&wm->jobs);
        BLI_listbase_clear(&wm->drags);
        
@@@ -6553,11 -6286,6 +6553,11 @@@ static void lib_link_windowmanager(File
                if (wm->id.tag & LIB_TAG_NEED_LINK) {
                        /* Note: WM IDProperties are never written to file, hence no need to read/link them here. */
                        for (win = wm->windows.first; win; win = win->next) {
 +                              if (win->workspace_hook) { /* NULL for old files */
 +                                      lib_link_workspace_instance_hook(fd, win->workspace_hook, &wm->id);
 +                              }
 +                              win->scene = newlibadr(fd, wm->id.lib, win->scene);
 +                              /* deprecated, but needed for versioning (will be NULL'ed then) */
                                win->screen = newlibadr(fd, NULL, win->screen);
                        }
                        
@@@ -6643,9 -6371,13 +6643,9 @@@ static void lib_link_screen(FileData *f
                        IDP_LibLinkProperty(sc->id.properties, fd);
                        id_us_ensure_real(&sc->id);
  
 +                      /* deprecated, but needed for versioning (will be NULL'ed then) */
                        sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
  
 -                      /* this should not happen, but apparently it does somehow. Until we figure out the cause,
 -                       * just assign first available scene */
 -                      if (!sc->scene)
 -                              sc->scene = main->scene.first;
 -
                        sc->animtimer = NULL; /* saved in rare cases */
                        sc->scrubbing = false;
                        
                                                case SPACE_VIEW3D:
                                                {
                                                        View3D *v3d = (View3D*) sl;
 -                                                      BGpic *bgpic = NULL;
  
                                                        v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
                                                        v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
  
 -                                                      /* should be do_versions but not easy adding into the listbase */
 -                                                      if (v3d->bgpic) {
 -                                                              v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic);
 -                                                              BLI_addtail(&v3d->bgpicbase, bgpic);
 -                                                              v3d->bgpic = NULL;
 -                                                      }
 -
 -                                                      for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
 -                                                              bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima);
 -                                                              bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip);
 -                                                      }
                                                        if (v3d->localvd) {
                                                                v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera);
                                                        }
@@@ -6941,60 -6685,88 +6941,60 @@@ static void lib_link_clipboard_restore(
        BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
  }
  
 -/* called from kernel/blender.c */
 -/* used to link a file (without UI) to the current UI */
 -/* note that it assumes the old pointers in UI are still valid, so old Main is not freed */
 -void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *curscene)
 +static void lib_link_workspace_scene_data_restore(wmWindow *win, Scene *scene)
  {
 -      wmWindow *win;
 -      wmWindowManager *wm;
 -      bScreen *sc;
 -      ScrArea *sa;
 +      bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
  
 -      struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
 +      for (ScrArea *area = screen->areabase.first; area; area = area->next) {
 +              for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
 +                      if (sl->spacetype == SPACE_VIEW3D) {
 +                              View3D *v3d = (View3D *)sl;
  
 -      /* first windowmanager */
 -      for (wm = newmain->wm.first; wm; wm = wm->id.next) {
 -              for (win= wm->windows.first; win; win= win->next) {
 -                      win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL);
 -                      
 -                      if (win->screen == NULL)
 -                              win->screen = curscreen;
 -                      
 -                      win->screen->winid = win->winid;
 +                              if (v3d->camera == NULL || v3d->scenelock) {
 +                                      v3d->camera = scene->camera;
 +                              }
 +
 +                              if (v3d->localvd) {
 +                                      /*Base *base;*/
 +
 +                                      v3d->localvd->camera = scene->camera;
 +
 +                                      /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
 +#if 0                         /* XXX  regionlocalview ? */
 +                                      for (base= sc->scene->base.first; base; base= base->next) {
 +                                              if (base->lay & v3d->lay) break;
 +                                      }
 +                                      if (base==NULL) {
 +                                              v3d->lay= v3d->localvd->lay;
 +                                              v3d->layact= v3d->localvd->layact;
 +                                              MEM_freeN(v3d->localvd);
 +                                              v3d->localvd= NULL;
 +                                      }
 +#endif
 +                              }
 +                              else if (v3d->scenelock) {
 +                                      v3d->lay = scene->lay;
 +                              }
 +                      }
                }
        }
 -      
 -      
 -      for (sc = newmain->screen.first; sc; sc = sc->id.next) {
 -              Scene *oldscene = sc->scene;
 -              
 -              sc->scene= restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL);
 -              if (sc->scene == NULL)
 -                      sc->scene = curscene;
 -              
 -              /* keep cursor location through undo */
 -              copy_v3_v3(sc->scene->cursor, oldscene->cursor);
 -              
 -              for (sa = sc->areabase.first; sa; sa = sa->next) {
 -                      SpaceLink *sl;
 -                      
 -                      for (sl = sa->spacedata.first; sl; sl = sl->next) {
 +}
 +
 +static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, Main *newmain, WorkSpaceLayout *layout)
 +{
 +      bScreen *screen = BKE_workspace_layout_screen_get(layout);
 +
 +      /* avoid conflicts with 2.8x branch */
 +      {
 +              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
                                if (sl->spacetype == SPACE_VIEW3D) {
                                        View3D *v3d = (View3D *)sl;
 -                                      BGpic *bgpic;
                                        ARegion *ar;
                                        
 -                                      if (v3d->scenelock)
 -                                              v3d->camera = NULL; /* always get from scene */
 -                                      else
 -                                              v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
 -                                      if (v3d->camera == NULL)
 -                                              v3d->camera = sc->scene->camera;
 +                                      v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
                                        v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL);
 -                                      
 -                                      for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
 -                                              if ((bgpic->ima = restore_pointer_by_name(id_map, (ID *)bgpic->ima, USER_IGNORE))) {
 -                                                      id_us_plus((ID *)bgpic->ima);
 -                                              }
 -                                              if ((bgpic->clip = restore_pointer_by_name(id_map, (ID *)bgpic->clip, USER_IGNORE))) {
 -                                                      id_us_plus((ID *)bgpic->clip);
 -                                              }
 -                                      }
 -                                      if (v3d->localvd) {
 -                                              /*Base *base;*/
 -                                              
 -                                              v3d->localvd->camera = sc->scene->camera;
 -                                              
 -                                              /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
 -#if 0                                 /* XXX  regionlocalview ? */
 -                                              for (base= sc->scene->base.first; base; base= base->next) {
 -                                                      if (base->lay & v3d->lay) break;
 -                                              }
 -                                              if (base==NULL) {
 -                                                      v3d->lay= v3d->localvd->lay;
 -                                                      v3d->layact= v3d->localvd->layact;
 -                                                      MEM_freeN(v3d->localvd); 
 -                                                      v3d->localvd= NULL;
 -                                              }
 -#endif
 -                                      }
 -                                      else if (v3d->scenelock) {
 -                                              v3d->lay = sc->scene->lay;
 -                                      }
 -                                      
 +
                                        /* not very nice, but could help */
                                        if ((v3d->layact & v3d->lay) == 0) v3d->layact = v3d->lay;
  
                        }
                }
        }
 +}
 +
 +/**
 + * Used to link a file (without UI) to the current UI.
 + * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
 + */
 +void blo_lib_link_restore(Main *newmain, wmWindowManager *curwm, Scene *curscene, ViewLayer *cur_view_layer)
 +{
 +      struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
 +
 +      for (WorkSpace *workspace = newmain->workspaces.first; workspace; workspace = workspace->id.next) {
 +              ListBase *layouts = BKE_workspace_layouts_get(workspace);
 +
 +              for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
 +                      lib_link_workspace_layout_restore(id_map, newmain, layout);
 +              }
 +              BKE_workspace_view_layer_set(workspace, cur_view_layer, curscene);
 +      }
 +
 +      for (wmWindow *win = curwm->windows.first; win; win = win->next) {
 +              WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
 +              ID *workspace_id = (ID *)workspace;
 +              Scene *oldscene = win->scene;
 +
 +              workspace = restore_pointer_by_name(id_map, workspace_id, USER_REAL);
 +              BKE_workspace_active_set(win->workspace_hook, workspace);
 +              win->scene = restore_pointer_by_name(id_map, (ID *)win->scene, USER_REAL);
 +              if (win->scene == NULL) {
 +                      win->scene = curscene;
 +              }
 +              BKE_workspace_active_set(win->workspace_hook, workspace);
 +
 +              /* keep cursor location through undo */
 +              copy_v3_v3(win->scene->cursor, oldscene->cursor);
 +              lib_link_workspace_scene_data_restore(win, win->scene);
 +
 +              BLI_assert(win->screen == NULL);
 +      }
  
        /* update IDs stored in all possible clipboards */
        lib_link_clipboard_restore(id_map);
@@@ -7287,7 -7021,6 +7287,7 @@@ static void direct_link_region(FileDat
                                rv3d->sms = NULL;
                                rv3d->smooth_timer = NULL;
                                rv3d->compositor = NULL;
 +                              rv3d->viewport = NULL;
                        }
                }
        }
        ar->type = NULL;
        ar->swap = 0;
        ar->do_draw = 0;
 +      ar->manipulator_map = NULL;
        ar->regiontimer = NULL;
        memset(&ar->drawrct, 0, sizeof(ar->drawrct));
  }
@@@ -7351,8 -7083,6 +7351,8 @@@ static bool direct_link_screen(FileDat
        sc->mainwin = sc->subwinactive= 0;      /* indices */
        sc->swap = 0;
  
 +      sc->preview = direct_link_preview_image(fd, sc->preview);
 +
        /* edges */
        for (se = sc->edgebase.first; se; se = se->next) {
                se->v1 = newdataadr(fd, se->v1);
                        
                        if (sl->spacetype == SPACE_VIEW3D) {
                                View3D *v3d= (View3D*) sl;
 -                              BGpic *bgpic;
 -                              
                                v3d->flag |= V3D_INVALID_BACKBUF;
                                
 -                              link_list(fd, &v3d->bgpicbase);
 -                              
 -                              /* should be do_versions except this doesnt fit well there */
 -                              if (v3d->bgpic) {
 -                                      bgpic = newdataadr(fd, v3d->bgpic);
 -                                      BLI_addtail(&v3d->bgpicbase, bgpic);
 -                                      v3d->bgpic = NULL;
 -                              }
 -                      
 -                              for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next)
 -                                      bgpic->iuser.ok = 1;
 -                              
                                if (v3d->gpd) {
                                        v3d->gpd = newdataadr(fd, v3d->gpd);
                                        direct_link_gpencil(fd, v3d->gpd);
@@@ -7704,26 -7448,6 +7704,26 @@@ static void fix_relpaths_library(const 
        }
  }
  
 +/* ************ READ PROBE ***************** */
 +
 +static void lib_link_lightprobe(FileData *fd, Main *main)
 +{
 +      for (LightProbe *prb = main->speaker.first; prb; prb = prb->id.next) {
 +              if (prb->id.tag & LIB_TAG_NEED_LINK) {
 +                      IDP_LibLinkProperty(prb->id.properties, fd);
 +                      lib_link_animdata(fd, &prb->id, prb->adt);
 +
 +                      prb->id.tag &= ~LIB_TAG_NEED_LINK;
 +              }
 +      }
 +}
 +
 +static void direct_link_lightprobe(FileData *fd, LightProbe *prb)
 +{
 +      prb->adt = newdataadr(fd, prb->adt);
 +      direct_link_animdata(fd, prb->adt);
 +}
 +
  /* ************ READ SPEAKER ***************** */
  
  static void lib_link_speaker(FileData *fd, Main *main)
@@@ -7803,61 -7527,30 +7803,61 @@@ static void direct_link_group(FileData 
        link_list(fd, &group->gobject);
  
        group->preview = direct_link_preview_image(fd, group->preview);
 +
 +      /* This runs before the very first doversion. */
 +      if (group->collection != NULL) {
 +              group->collection = newdataadr(fd, group->collection);
 +              direct_link_scene_collection(fd, group->collection);
 +      }
 +
 +      if (group->view_layer != NULL) {
 +              group->view_layer = newdataadr(fd, group->view_layer);
 +              direct_link_view_layer(fd, group->view_layer);
 +      }
  }
  
  static void lib_link_group(FileData *fd, Main *main)
  {
        for (Group *group = main->group.first; group; group = group->id.next) {
                if (group->id.tag & LIB_TAG_NEED_LINK) {
 +                      group->id.tag &= ~LIB_TAG_NEED_LINK;
                        IDP_LibLinkProperty(group->id.properties, fd);
 -                      
 -                      bool add_us = false;
 -                      
 -                      for (GroupObject *go = group->gobject.first; go; go = go->next) {
 -                              go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
 -                              if (go->ob) {
 -                                      go->ob->flag |= OB_FROMGROUP;
 -                                      /* if group has an object, it increments user... */
 -                                      add_us = true;
 +
 +                      if (group->view_layer == NULL) {
 +                              /* Old file, this is required for doversion. */
 +                              bool add_us = false;
 +
 +                              GroupObject *go, *gon;
 +                              go = group->gobject.first;
 +                              while (go) {
 +                                      gon = go->next;
 +                                      go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
 +                                      if (go->ob != NULL) {
 +                                              go->ob->flag |= OB_FROMGROUP;
 +                                              /* If group has an object, it increments user... */
 +                                              add_us = true;
 +                                      }
 +                                      else {
 +                                              /* Remove NULL objects. */
 +                                              BLI_remlink(&group->gobject, go);
 +                                              MEM_freeN(go);
 +                                      }
 +                                      go =  gon;
 +                              }
 +
 +                              if (add_us) {
 +                                      id_us_ensure_real(&group->id);
                                }
 +                              /* The rest of the read code is only for new files, skip it. */
 +                              continue;
                        }
 -                      if (add_us) {
 +
 +                      lib_link_scene_collection(fd, group->id.lib, group->collection);
 +                      lib_link_view_layer(fd, group->id.lib, group->view_layer);
 +
 +                      if (!BLI_listbase_is_empty(&group->view_layer->object_bases)) {
                                id_us_ensure_real(&group->id);
                        }
 -                      BKE_group_object_unlink(group, NULL, NULL, NULL);       /* removes NULL entries */
 -
 -                      group->id.tag &= ~LIB_TAG_NEED_LINK;
                }
        }
  }
@@@ -8370,7 -8063,6 +8370,7 @@@ static const char *dataname(short id_co
                case ID_VF: return "Data from VF";
                case ID_TXT     : return "Data from TXT";
                case ID_SPK: return "Data from SPK";
 +              case ID_LP: return "Data from LP";
                case ID_SO: return "Data from SO";
                case ID_NT: return "Data from NT";
                case ID_BR: return "Data from BR";
                case ID_MSK: return "Data from MSK";
                case ID_LS: return "Data from LS";
                case ID_CF: return "Data from CF";
 +              case ID_WS: return "Data from WS";
        }
        return "Data from Lib Block";
        
@@@ -8547,7 -8238,7 +8547,7 @@@ static BHead *read_libblock(FileData *f
                        wrong_id = direct_link_screen(fd, (bScreen *)id);
                        break;
                case ID_SCE:
 -                      direct_link_scene(fd, (Scene *)id);
 +                      direct_link_scene(fd, (Scene *)id, main);
                        break;
                case ID_OB:
                        direct_link_object(fd, (Object *)id);
                case ID_SO:
                        direct_link_sound(fd, (bSound *)id);
                        break;
 +              case ID_LP:
 +                      direct_link_lightprobe(fd, (LightProbe *)id);
 +                      break;
                case ID_GR:
                        direct_link_group(fd, (Group *)id);
                        break;
                case ID_CF:
                        direct_link_cachefile(fd, (CacheFile *)id);
                        break;
 +              case ID_WS:
 +                      direct_link_workspace(fd, (WorkSpace *)id, main);
 +                      break;
        }
        
        oldnewmap_free_unused(fd->datamap);
@@@ -8693,8 -8378,7 +8693,8 @@@ static BHead *read_global(BlendFileDat
        
        bfd->curscreen = fg->curscreen;
        bfd->curscene = fg->curscene;
 -      
 +      bfd->cur_view_layer = fg->cur_view_layer;
 +
        MEM_freeN(fg);
        
        fd->globalf = bfd->globalf;
  /* note, this has to be kept for reading older files... */
  static void link_global(FileData *fd, BlendFileData *bfd)
  {
 +      bfd->cur_view_layer = newglobadr(fd, bfd->cur_view_layer);
        bfd->curscreen = newlibadr(fd, NULL, bfd->curscreen);
        bfd->curscene = newlibadr(fd, NULL, bfd->curscene);
        // this happens in files older than 2.35
        }
  }
  
 -static void convert_tface_mt(FileData *fd, Main *main)
 -{
 -      Main *gmain;
 -      
 -      /* this is a delayed do_version (so it can create new materials) */
 -      if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 3)) {
 -              //XXX hack, material.c uses G.main all over the place, instead of main
 -              // temporarily set G.main to the current main
 -              gmain = G.main;
 -              G.main = main;
 -              
 -              if (!(do_version_tface(main))) {
 -                      BKE_report(fd->reports, RPT_WARNING, "Texface conversion problem (see error in console)");
 -              }
 -              
 -              //XXX hack, material.c uses G.main allover the place, instead of main
 -              G.main = gmain;
 -      }
 -}
 -
  /* initialize userdef with non-UI dependency stuff */
  /* other initializers (such as theme color defaults) go to resources.c */
  static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
@@@ -8768,7 -8471,6 +8768,7 @@@ static void do_versions(FileData *fd, L
        blo_do_versions_250(fd, lib, main);
        blo_do_versions_260(fd, lib, main);
        blo_do_versions_270(fd, lib, main);
 +      blo_do_versions_280(fd, lib, main);
  
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
        /* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
@@@ -8782,15 -8484,12 +8782,15 @@@ static void do_versions_after_linking(M
  //           main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
  
        do_versions_after_linking_270(main);
 +      do_versions_after_linking_280(main);
  }
  
  static void lib_link_all(FileData *fd, Main *main)
  {
        oldnewmap_sort(fd);
        
 +      lib_link_id(fd, main);
 +
        /* No load UI for undo memfiles */
        if (fd->memfile == NULL) {
                lib_link_windowmanager(fd, main);
        lib_link_text(fd, main);
        lib_link_camera(fd, main);
        lib_link_speaker(fd, main);
 +      lib_link_lightprobe(fd, main);
        lib_link_sound(fd, main);
        lib_link_group(fd, main);
        lib_link_armature(fd, main);
        lib_link_linestyle(fd, main);
        lib_link_gpencil(fd, main);
        lib_link_cachefiles(fd, main);
 +      lib_link_workspaces(fd, main);
  
        lib_link_library(fd, main);    /* only init users */
  }
@@@ -9016,12 -8713,6 +9016,12 @@@ BlendFileData *blo_read_file_internal(F
  
        BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false);
  
 +      /* Now that all our data-blocks are loaded, we can re-generate overrides from their references. */
 +      if (fd->memfile == NULL) {
 +              /* Do not apply in undo case! */
 +              BKE_main_override_static_update(bfd->main);
 +      }
 +
        lib_verify_nodetree(bfd->main, true);
        fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */
        
@@@ -9222,11 -8913,6 +9222,11 @@@ static void expand_doit_library(void *f
                        }
                }
                else {
 +                      /* in 2.50+ file identifier for screens is patched, forward compatibility */
 +                      if (bhead->code == ID_SCRN) {
 +                              bhead->code = ID_SCR;
 +                      }
 +
                        id = is_yet_read(fd, mainvar, bhead);
                        if (id == NULL) {
                                read_libblock(fd, mainvar, bhead, LIB_TAG_TESTIND, NULL);
@@@ -9460,11 -9146,6 +9460,11 @@@ static void expand_group(FileData *fd, 
        for (go = group->gobject.first; go; go = go->next) {
                expand_doit(fd, mainvar, go->ob);
        }
 +
 +      if (group->collection != NULL) {
 +              expand_scene_collection(fd, mainvar, group->collection);
 +      }
 +
  }
  
  static void expand_key(FileData *fd, Main *mainvar, Key *key)
@@@ -9546,10 -9227,6 +9546,10 @@@ static void expand_material(FileData *f
        
        if (ma->group)
                expand_doit(fd, mainvar, ma->group);
 +
 +      if (ma->edit_image) {
 +              expand_doit(fd, mainvar, ma->edit_image);
 +      }
  }
  
  static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la)
@@@ -9639,7 -9316,9 +9639,7 @@@ static void expand_curve(FileData *fd, 
  
  static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me)
  {
 -      CustomDataLayer *layer;
 -      TFace *tf;
 -      int a, i;
 +      int a;
        
        if (me->adt)
                expand_animdata(fd, mainvar, me->adt);
        
        expand_doit(fd, mainvar, me->key);
        expand_doit(fd, mainvar, me->texcomesh);
 -      
 -      if (me->tface) {
 -              tf = me->tface;
 -              for (i=0; i<me->totface; i++, tf++) {
 -                      if (tf->tpage)
 -                              expand_doit(fd, mainvar, tf->tpage);
 -              }
 -      }
 -
 -      if (me->mface && !me->mpoly) {
 -              MTFace *mtf;
 -
 -              for (a = 0; a < me->fdata.totlayer; a++) {
 -                      layer = &me->fdata.layers[a];
 -
 -                      if (layer->type == CD_MTFACE) {
 -                              mtf = (MTFace *) layer->data;
 -                              for (i = 0; i < me->totface; i++, mtf++) {
 -                                      if (mtf->tpage)
 -                                              expand_doit(fd, mainvar, mtf->tpage);
 -                              }
 -                      }
 -              }
 -      }
 -      else {
 -              MTexPoly *mtp;
 -
 -              for (a = 0; a < me->pdata.totlayer; a++) {
 -                      layer = &me->pdata.layers[a];
 -
 -                      if (layer->type == CD_MTEXPOLY) {
 -                              mtp = (MTexPoly *) layer->data;
 -
 -                              for (i = 0; i < me->totpoly; i++, mtp++) {
 -                                      if (mtp->tpage)
 -                                              expand_doit(fd, mainvar, mtp->tpage);
 -                              }
 -                      }
 -              }
 -      }
  }
  
  /* temp struct used to transport needed info to expand_constraint_cb() */
@@@ -9892,29 -9611,15 +9892,29 @@@ static void expand_object(FileData *fd
        }
  }
  
 +static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc)
 +{
 +      for (LinkData *link = sc->objects.first; link; link = link->next) {
 +              expand_doit(fd, mainvar, link->data);
 +      }
 +
 +      for (LinkData *link = sc->filter_objects.first; link; link = link->next) {
 +              expand_doit(fd, mainvar, link->data);
 +      }
 +
 +      for (SceneCollection *nsc= sc->scene_collections.first; nsc; nsc = nsc->next) {
 +              expand_scene_collection(fd, mainvar, nsc);
 +      }
 +}
 +
  static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
  {
 -      Base *base;
        SceneRenderLayer *srl;
        FreestyleModuleConfig *module;
        FreestyleLineSet *lineset;
        
 -      for (base = sce->base.first; base; base = base->next) {
 -              expand_doit(fd, mainvar, base->object);
 +      for (Base *base_legacy = sce->base.first; base_legacy; base_legacy = base_legacy->next) {
 +              expand_doit(fd, mainvar, base_legacy->object);
        }
        expand_doit(fd, mainvar, sce->camera);
        expand_doit(fd, mainvar, sce->world);
        
        for (srl = sce->r.layers.first; srl; srl = srl->next) {
                expand_doit(fd, mainvar, srl->mat_override);
 -              expand_doit(fd, mainvar, srl->light_override);
                for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
                        if (module->script)
                                expand_doit(fd, mainvar, module->script);
                        expand_doit(fd, mainvar, lineset->linestyle);
                }
        }
 -      
 +
 +      for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
 +              for (module = view_layer->freestyle_config.modules.first; module; module = module->next) {
 +                      if (module->script) {
 +                              expand_doit(fd, mainvar, module->script);
 +                      }
 +              }
 +
 +              for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
 +                      if (lineset->group) {
 +                              expand_doit(fd, mainvar, lineset->group);
 +                      }
 +                      expand_doit(fd, mainvar, lineset->linestyle);
 +              }
 +      }
 +
        if (sce->r.dometext)
                expand_doit(fd, mainvar, sce->gm.dome.warptext);
        
        }
  
        expand_doit(fd, mainvar, sce->clip);
 +
 +      expand_scene_collection(fd, mainvar, sce->collection);
  }
  
  static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
@@@ -10023,12 -9712,6 +10023,12 @@@ static void expand_sound(FileData *fd, 
        expand_doit(fd, mainvar, snd->ipo); // XXX deprecated - old animation system
  }
  
 +static void expand_lightprobe(FileData *fd, Main *mainvar, LightProbe *prb)
 +{
 +      if (prb->adt)
 +              expand_animdata(fd, mainvar, prb->adt);
 +}
 +
  static void expand_movieclip(FileData *fd, Main *mainvar, MovieClip *clip)
  {
        if (clip->adt)
@@@ -10102,15 -9785,6 +10102,15 @@@ static void expand_gpencil(FileData *fd
                expand_animdata(fd, mainvar, gpd->adt);
  }
  
 +static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace)
 +{
 +      ListBase *layouts = BKE_workspace_layouts_get(workspace);
 +
 +      for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
 +              expand_doit(fd, mainvar, BKE_workspace_layout_screen_get(layout));
 +      }
 +}
 +
  /**
   * Set the callback func used over all ID data found by \a BLO_expand_main func.
   *
@@@ -10189,9 -9863,6 +10189,9 @@@ void BLO_expand_main(void *fdhandle, Ma
                                        case ID_SO:
                                                expand_sound(fd, mainvar, (bSound *)id);
                                                break;
 +                                      case ID_LP:
 +                                              expand_lightprobe(fd, mainvar, (LightProbe *)id);
 +                                              break;
                                        case ID_AR:
                                                expand_armature(fd, mainvar, (bArmature *)id);
                                                break;
                                        case ID_CF:
                                                expand_cachefile(fd, mainvar, (CacheFile *)id);
                                                break;
 +                                      case ID_WS:
 +                                              expand_workspace(fd, mainvar, (WorkSpace *)id);
                                        default:
                                                break;
                                        }
@@@ -10252,7 -9921,7 +10252,7 @@@ static bool object_in_any_scene(Main *m
        Scene *sce;
        
        for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
 -              if (BKE_scene_base_find(sce, ob)) {
 +              if (BKE_scene_object_find(sce, ob)) {
                        return true;
                }
        }
        return false;
  }
  
 -static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Library *lib, const short flag)
 +static void give_base_to_objects(
 +        Main *mainvar, Scene *scene, ViewLayer *view_layer, Library *lib, const short flag)
  {
        Object *ob;
        Base *base;
 -      const unsigned int active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0;
 +      SceneCollection *scene_collection = NULL;
        const bool is_link = (flag & FILE_LINK) != 0;
  
        BLI_assert(scene);
  
 -      /* give all objects which are LIB_TAG_INDIRECT a base, or for a group when *lib has been set */
 +      /* Give all objects which are LIB_TAG_INDIRECT a base, or for a group when *lib has been set. */
        for (ob = mainvar->object.first; ob; ob = ob->id.next) {
                if ((ob->id.tag & LIB_TAG_INDIRECT) && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0) {
                        bool do_it = false;
                        }
  
                        if (do_it) {
 -                              base = MEM_callocN(sizeof(Base), __func__);
 -                              BLI_addtail(&scene->base, base);
 +                              CLAMP_MIN(ob->id.us, 0);
  
 -                              if (active_lay) {
 -                                      ob->lay = active_lay;
 +                              if (scene_collection == NULL) {
 +                                      scene_collection = get_scene_collection_active_or_create(scene, view_layer, FILE_ACTIVE_COLLECTION);
                                }
 +
 +                              BKE_collection_object_add(&scene->id, scene_collection, ob);
 +                              base = BKE_view_layer_base_find(view_layer, ob);
 +                              BKE_scene_object_base_flag_sync_from_base(base);
 +
                                if (flag & FILE_AUTOSELECT) {
                                        /* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag,
                                         * but it will miss objects from non-instanciated groups... */
 -                                      ob->flag |= SELECT;
 -                                      /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
 +                                      if (base->flag & BASE_SELECTABLED) {
 +                                              base->flag |= BASE_SELECTED;
 +                                              BKE_scene_object_base_flag_sync_from_base(base);
 +                                      }
 +                                      /* Do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level. */
                                }
  
 -                              base->object = ob;
 -                              base->lay = ob->lay;
 -                              base->flag = ob->flag;
 -
 -                              CLAMP_MIN(ob->id.us, 0);
 -                              id_us_plus_no_lib((ID *)ob);
 -
                                ob->id.tag &= ~LIB_TAG_INDIRECT;
                                ob->id.tag |= LIB_TAG_EXTERN;
                        }
  }
  
  static void give_base_to_groups(
 -        Main *mainvar, Scene *scene, View3D *v3d, Library *UNUSED(lib), const short UNUSED(flag))
 +        Main *mainvar, Scene *scene, ViewLayer *view_layer, Library *UNUSED(lib), const short UNUSED(flag))
  {
        Group *group;
        Base *base;
        Object *ob;
 -      const unsigned int active_lay = BKE_screen_view3d_layer_active(v3d, scene);
 +      SceneCollection *scene_collection;
 +
 +      /* If the group is empty this function is not even called, so it's safe to ensure a collection at this point. */
 +      scene_collection = get_scene_collection_active_or_create(scene, view_layer, FILE_ACTIVE_COLLECTION);
  
 -      /* give all objects which are tagged a base */
 +      /* Give all objects which are tagged a base. */
        for (group = mainvar->group.first; group; group = group->id.next) {
                if (group->id.tag & LIB_TAG_DOIT) {
 -                      /* any indirect group should not have been tagged */
 +                      /* Any indirect group should not have been tagged. */
                        BLI_assert((group->id.tag & LIB_TAG_INDIRECT) == 0);
  
 -                      /* BKE_object_add(...) messes with the selection */
 +                      /* BKE_object_add(...) messes with the selection. */
                        ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2);
                        ob->type = OB_EMPTY;
 -                      ob->lay = active_lay;
  
 -                      /* assign the base */
 -                      base = BKE_scene_base_add(scene, ob);
 -                      base->flag |= SELECT;
 -                      base->object->flag = base->flag;
 -                      DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 -                      scene->basact = base;
 +                      BKE_collection_object_add(&scene->id, scene_collection, ob);
 +                      base = BKE_view_layer_base_find(view_layer, ob);
 +
 +                      if (base->flag & BASE_SELECTABLED) {
 +                              base->flag |= BASE_SELECTED;
 +                      }
 +
 +                      BKE_scene_object_base_flag_sync_from_base(base);
 +                      DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 +                      view_layer->basact = base;
  
 -                      /* assign the group */
 +                      /* Assign the group. */
                        ob->dup_group = group;
                        ob->transflag |= OB_DUPLIGROUP;
                        copy_v3_v3(ob->loc, scene->cursor);
@@@ -10421,43 -10083,31 +10421,43 @@@ static ID *link_named_part
        return id;
  }
  
 -static void link_object_postprocess(ID *id, Scene *scene, View3D *v3d, const int flag)
 +static SceneCollection *get_scene_collection_active_or_create(
 +        struct Scene *scene, struct ViewLayer *view_layer, const int flag)
 +{
 +      LayerCollection *lc = NULL;
 +
 +      if (flag & FILE_ACTIVE_COLLECTION) {
 +              lc = BKE_layer_collection_get_active_ensure(scene, view_layer);
 +      }
 +      else {
 +              SceneCollection *sc = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL);
 +              lc = BKE_collection_link(view_layer, sc);
 +      }
 +
 +      return lc->scene_collection;
 +}
 +
 +static void link_object_postprocess(ID *id, Scene *scene, ViewLayer *view_layer, const int flag)
  {
        if (scene) {
 +              /* link to scene */
                Base *base;
                Object *ob;
 -
 -              base = MEM_callocN(sizeof(Base), "app_nam_part");
 -              BLI_addtail(&scene->base, base);
 +              SceneCollection *sc;
  
                ob = (Object *)id;
 -
 -              /* link at active layer (view3d if available in context, else scene one */
 -              if (flag & FILE_ACTIVELAY) {
 -                      ob->lay = BKE_screen_view3d_layer_active(v3d, scene);
 -              }
 -
                ob->mode = OB_MODE_OBJECT;
 -              base->lay = ob->lay;
 -              base->object = ob;
 -              base->flag = ob->flag;
 -              id_us_plus_no_lib((ID *)ob);
 +
 +              sc =  get_scene_collection_active_or_create(scene, view_layer, flag);
 +              BKE_collection_object_add(&scene->id, sc, ob);
 +              base = BKE_view_layer_base_find(view_layer, ob);
 +              BKE_scene_object_base_flag_sync_from_base(base);
  
                if (flag & FILE_AUTOSELECT) {
 -                      base->flag |= SELECT;
 -                      base->object->flag = base->flag;
 +                      if (base->flag & BASE_SELECTABLED) {
 +                              base->flag |= BASE_SELECTED;
 +                              BKE_scene_object_base_flag_sync_from_base(base);
 +                      }
                        /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
                }
        }
@@@ -10500,12 -10150,12 +10500,12 @@@ void BLO_library_link_copypaste(Main *m
  
  static ID *link_named_part_ex(
          Main *mainl, FileData *fd, const short idcode, const char *name, const int flag,
 -        Scene *scene, View3D *v3d)
 +        Scene *scene, ViewLayer *view_layer)
  {
        ID *id = link_named_part(mainl, fd, idcode, name, flag);
  
        if (id && (GS(id->name) == ID_OB)) {    /* loose object: give a base */
 -              link_object_postprocess(id, scene, v3d, flag);
 +              link_object_postprocess(id, scene, view_layer, flag);
        }
        else if (id && (GS(id->name) == ID_GR)) {
                /* tag as needing to be instantiated */
@@@ -10547,10 -10197,10 +10547,10 @@@ ID *BLO_library_link_named_part(Main *m
  ID *BLO_library_link_named_part_ex(
          Main *mainl, BlendHandle **bh,
          const short idcode, const char *name, const int flag,
 -        Scene *scene, View3D *v3d)
 +        Scene *scene, ViewLayer *view_layer)
  {
        FileData *fd = (FileData*)(*bh);
 -      return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d);
 +      return link_named_part_ex(mainl, fd, idcode, name, flag, scene, view_layer);
  }
  
  static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
@@@ -10663,7 -10313,7 +10663,7 @@@ static void split_main_newid(Main *main
  }
  
  /* scene and v3d may be NULL. */
 -static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d)
 +static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, ViewLayer *view_layer)
  {
        Main *mainvar;
        Library *curlib;
         * Only directly linked objects & groups are instantiated by `BLO_library_link_named_part_ex()` & co,
         * here we handle indirect ones and other possible edge-cases. */
        if (scene) {
 -              give_base_to_objects(mainvar, scene, v3d, curlib, flag);
 +              give_base_to_objects(mainvar, scene, view_layer, curlib, flag);
  
                if (flag & FILE_GROUP_INSTANCE) {
 -                      give_base_to_groups(mainvar, scene, v3d, curlib, flag);
 +                      give_base_to_groups(mainvar, scene, view_layer, curlib, flag);
                }
        }
        else {
   * \param bh The blender file handle (WARNING! may be freed by this function!).
   * \param flag Options for linking, used for instantiating.
   * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
 - * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
 + * \param view_layer The scene layer in which to instantiate objects/groups (if NULL, no instantiation is done).
   */
 -void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, View3D *v3d)
 +void BLO_library_link_end(Main *mainl, BlendHandle **bh, int flag, Scene *scene, ViewLayer *view_layer)
  {
        FileData *fd = (FileData*)(*bh);
 -      library_link_end(mainl, &fd, flag, scene, v3d);
 +      library_link_end(mainl, &fd, flag, scene, view_layer);
        *bh = (BlendHandle*)fd;
  }
  
index e928da58e8759e61ca0af75ee89f62b3e6fee5ad,8f91a82676007ac7f2a9e3c4473c8f42a7ddb029..ee406acb4900fbd9d14e901513267f892d9fc591
@@@ -49,8 -49,6 +49,8 @@@ extern "C" 
  #include "BKE_library.h"
  #include "BKE_main.h"
  #include "BKE_node.h"
 +#include "BKE_scene.h"
 +#include "BKE_workspace.h"
  
  #define new new_
  #include "BKE_screen.h"
  #include "intern/depsgraph_intern.h"
  #include "util/deg_util_foreach.h"
  
 +/* Define this in order to have more strict sanitization of what tagging flags
 + * are used for ID databnlocks. Ideally, we would always want this, but there
 + * are cases in generic modules (like IR remapping) where we don't want to spent
 + * lots of time trying to guess which components are to be updated.
 + */
 +// #define STRICT_COMPONENT_TAGGING
 +
  /* *********************** */
  /* Update Tagging/Flushing */
  
 -/* Legacy depsgraph did some special trickery for things like particle systems
 - * when tagging ID for an update. Ideally that tagging needs to become obsolete
 - * in favor of havng dedicated node for that which gets tagged, but for until
 - * design of those areas is more clear we'll do the same legacy code here.
 - *                                                                  - sergey -
 - */
 -#define DEPSGRAPH_USE_LEGACY_TAGGING
 -
 -namespace {
 +namespace DEG {
  
  /* Data-Based Tagging ------------------------------- */
  
@@@ -94,421 -93,138 +94,421 @@@ void lib_id_recalc_data_tag(Main *bmain
        DEG_id_type_tag(bmain, GS(id->name));
  }
  
 +namespace {
 +
 +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag);
 +
  void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
  {
 +      /* This bit of code ensures legacy object->recalc flags are still filled in
 +       * the same way as it was expected with the old dependency graph.
 +       *
 +       * This is because some areas like motion paths and likely some other
 +       * physics baking process are doing manual scene update on all the frames,
 +       * trying to minimize number of updates.
 +       *
 +       * But this flag will also let us to re-construct entry nodes for update
 +       * after relations update and after layer visibility changes.
 +       */
        if (flag) {
 -              /* This bit of code ensures legacy object->recalc flags
 -               * are still filled in the same way as it was expected
 -               * with the old dependency graph.
 -               *
 -               * This is because some areas like motion paths and likely
 -               * some other physics baking process are doing manual scene
 -               * update on all the frames, trying to minimize number of
 -               * updates.
 -               *
 -               * But this flag will also let us to re-construct entry
 -               * nodes for update after relations update and after layer
 -               * visibility changes.
 -               */
 -              ID_Type idtype = GS(id->name);
 -              if (idtype == ID_OB) {
 -                      Object *object = (Object *)id;
 -                      object->recalc |= (flag & OB_RECALC_ALL);
 -              }
 -
 -              if (flag & OB_RECALC_OB)
 +              if (flag & OB_RECALC_OB) {
                        lib_id_recalc_tag(bmain, id);
 -              if (flag & (OB_RECALC_DATA | PSYS_RECALC))
 +              }
 +              if (flag & (OB_RECALC_DATA | PSYS_RECALC)) {
                        lib_id_recalc_data_tag(bmain, id);
 +              }
        }
        else {
                lib_id_recalc_tag(bmain, id);
        }
  }
  
 -#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
 -void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag)
 +/* Special tagging  */
 +void id_tag_update_special_zero_flag(Depsgraph *graph, IDDepsNode *id_node)
  {
 -      if (flag) {
 -              Object *object;
 -              short idtype = GS(id->name);
 -              if (idtype == ID_PA) {
 -                      ParticleSystem *psys;
 -                      for (object = (Object *)bmain->object.first;
 -                           object != NULL;
 -                           object = (Object *)object->id.next)
 -                      {
 -                              for (psys = (ParticleSystem *)object->particlesystem.first;
 -                                   psys != NULL;
 -                                   psys = (ParticleSystem *)psys->next)
 -                              {
 -                                      if (&psys->part->id == id) {
 -                                              DEG_id_tag_update_ex(bmain, &object->id, flag & OB_RECALC_ALL);
 -                                              psys->recalc |= (flag & PSYS_RECALC);
 -                                      }
 -                              }
 +      /* NOTE: Full ID node update for now, need to minimize that i9n the future. */
 +      id_node->tag_update(graph);
 +}
 +
 +/* Tag corresponding to OB_RECALC_OB. */
 +void id_tag_update_object_transform(Depsgraph *graph, IDDepsNode *id_node)
 +{
 +      ComponentDepsNode *transform_comp =
 +              id_node->find_component(DEG_NODE_TYPE_TRANSFORM);
 +      if (transform_comp == NULL) {
 +#ifdef STRICT_COMPONENT_TAGGING
 +              DEG_ERROR_PRINTF("ERROR: Unable to find transform component for %s\n",
 +                               id_node->id_orig->name);
 +              BLI_assert(!"This is not supposed to happen!");
 +#endif
 +              return;
 +      }
 +      transform_comp->tag_update(graph);
 +}
 +
 +/* Tag corresponding to OB_RECALC_DATA. */
 +void id_tag_update_object_data(Depsgraph *graph, IDDepsNode *id_node)
 +{
 +      const ID_Type id_type = GS(id_node->id_orig->name);
 +      ComponentDepsNode *data_comp = NULL;
 +      switch (id_type) {
 +              case ID_OB:
 +              {
 +                      const Object *object = (Object *)id_node->id_orig;
 +                      switch (object->type) {
 +                              case OB_MESH:
 +                              case OB_CURVE:
 +                              case OB_SURF:
 +                              case OB_FONT:
 +                              case OB_MBALL:
 +                                      data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY);
 +                                      break;
 +                              case OB_ARMATURE:
 +                                      data_comp = id_node->find_component(DEG_NODE_TYPE_EVAL_POSE);
 +                                      break;
 +                              /* TODO(sergey): More cases here? */
 +                      }
 +                      break;
 +              }
 +              case ID_ME:
 +                      data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY);
 +                      break;
 +              case ID_PA:
 +                      return;
 +              case ID_LP:
 +                      data_comp = id_node->find_component(DEG_NODE_TYPE_PARAMETERS);
 +                      break;
 +              default:
 +                      break;
 +      }
 +      if (data_comp == NULL) {
 +#ifdef STRICT_COMPONENT_TAGGING
 +              DEG_ERROR_PRINTF("ERROR: Unable to find data component for %s\n",
 +                               id_node->id_orig->name);
 +              BLI_assert(!"This is not supposed to happen!");
 +#endif
 +              return;
 +      }
 +      data_comp->tag_update(graph);
 +      /* Special legacy compatibility code, tag data ID for update when object
 +       * is tagged for data update.
 +       */
 +      if (id_type == ID_OB) {
 +              Object *object = (Object *)id_node->id_orig;
 +              ID *data_id = (ID *)object->data;
 +              if (data_id != NULL) {
 +                      IDDepsNode *data_id_node = graph->find_id_node(data_id);
 +                      // BLI_assert(data_id_node != NULL);
 +                      /* TODO(sergey): Do we want more granular tags here? */
 +                      /* TODO(sergey): Hrm, during some operations it's possible to have
 +                       * object node existing but not it's data. For example, when making
 +                       * objects local. This is valid situation, but how can we distinguish
 +                       * that from someone trying to do stupid things with dependency
 +                       * graph?
 +                       */
 +                      if (data_id_node != NULL) {
 +                              data_id_node->tag_update(graph);
                        }
                }
        }
  }
 +
 +/* Tag corresponding to OB_RECALC_TIME. */
 +void id_tag_update_object_time(Depsgraph *graph, IDDepsNode *id_node)
 +{
 +      ComponentDepsNode *animation_comp =
 +              id_node->find_component(DEG_NODE_TYPE_ANIMATION);
 +      if (animation_comp == NULL) {
 +              /* It's not necessarily we've got animation component in cases when
 +               * we are tagging for time updates.
 +               */
 +              return;
 +      }
 +      animation_comp->tag_update(graph);
 +      /* TODO(sergey): More components to tag here? */
 +}
 +
 +void id_tag_update_particle(Depsgraph *graph, IDDepsNode *id_node, int tag)
 +{
 +      ComponentDepsNode *particle_comp =
 +              id_node->find_component(DEG_NODE_TYPE_PARAMETERS);
 +      ParticleSettings *particle_settings = (ParticleSettings *)id_node->id_orig;
 +      particle_settings->recalc |= (tag & PSYS_RECALC);
 +      if (particle_comp == NULL) {
 +#ifdef STRICT_COMPONENT_TAGGING
 +              DEG_ERROR_PRINTF("ERROR: Unable to find particle component for %s\n",
 +                               id_node->id_orig->name);
 +              BLI_assert(!"This is not supposed to happen!");
  #endif
 +              return;
 +      }
 +      particle_comp->tag_update(graph);
 +}
  
 -}  /* namespace */
 +void id_tag_update_shading(Depsgraph *graph, IDDepsNode *id_node)
 +{
 +      ComponentDepsNode *shading_comp;
 +      if (GS(id_node->id_orig->name) == ID_NT) {
 +              shading_comp = id_node->find_component(DEG_NODE_TYPE_SHADING_PARAMETERS);
 +      }
 +      else {
 +              shading_comp = id_node->find_component(DEG_NODE_TYPE_SHADING);
 +      }
 +      if (shading_comp == NULL) {
 +#ifdef STRICT_COMPONENT_TAGGING
 +              DEG_ERROR_PRINTF("ERROR: Unable to find shading component for %s\n",
 +                               id_node->id_orig->name);
 +              BLI_assert(!"This is not supposed to happen!");
 +#endif
 +              return;
 +      }
 +      shading_comp->tag_update(graph);
 +}
  
 -/* Tag all nodes in ID-block for update.
 - * This is a crude measure, but is most convenient for old code.
 - */
 -void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
 +/* Tag corresponding to DEG_TAG_COPY_ON_WRITE. */
 +void id_tag_update_copy_on_write(Depsgraph *graph, IDDepsNode *id_node)
 +{
 +      if (!DEG_depsgraph_use_copy_on_write()) {
 +              return;
 +      }
 +      ComponentDepsNode *cow_comp =
 +              id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
 +      OperationDepsNode *cow_node = cow_comp->get_entry_operation();
 +      cow_node->tag_update(graph);
 +}
 +
 +void id_tag_update_select_update(Depsgraph *graph, IDDepsNode *id_node)
  {
 -      DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
 -      DEG::IDDepsNode *node = deg_graph->find_id_node(id);
 -      lib_id_recalc_tag(bmain, id);
 +      ComponentDepsNode *component;
 +      OperationDepsNode *node = NULL;
 +      const ID_Type id_type = GS(id_node->id_orig->name);
 +      if (id_type == ID_SCE) {
 +              /* We need to flush base flags to all objects in a scene since we
 +               * don't know which ones changed. However, we don't want to update
 +               * the whole scene, so pick up some operation which will do as less
 +               * as possible.
 +               *
 +               * TODO(sergey): We can introduce explicit exit operation which
 +               * does nothing and which is only used to cascade flush down the
 +               * road.
 +               */
 +              component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS);
 +              BLI_assert(component != NULL);
 +              if (component != NULL) {
 +                      node = component->find_operation(DEG_OPCODE_VIEW_LAYER_DONE);
 +              }
 +      }
 +      else if (id_type == ID_OB) {
 +              component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS);
 +              /* NOTE: This component might be missing for indirectly linked
 +               * objects.
 +               */
 +              if (component != NULL) {
 +                      node = component->find_operation(DEG_OPCODE_OBJECT_BASE_FLAGS);
 +              }
 +      }
 +      else {
 +              component = id_node->find_component(DEG_NODE_TYPE_BATCH_CACHE);
 +              BLI_assert(component != NULL);
 +              if (component != NULL) {
 +                      node = component->find_operation(DEG_OPCODE_GEOMETRY_SELECT_UPDATE,
 +                                                       "", -1);
 +              }
 +      }
        if (node != NULL) {
 -              node->tag_update(deg_graph);
 +              node->tag_update(graph);
        }
  }
  
 -/* Tag given ID for an update in all the dependency graphs. */
 -void DEG_id_tag_update(ID *id, short flag)
 +void id_tag_update_base_flags(Depsgraph *graph, IDDepsNode *id_node)
  {
 -      DEG_id_tag_update_ex(G.main, id, flag);
 +      ComponentDepsNode *component;
 +      OperationDepsNode *node = NULL;
 +      const ID_Type id_type = GS(id_node->id_orig->name);
 +      if (id_type == ID_SCE) {
 +              component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS);
 +              if (component == NULL) {
 +                      return;
 +              }
 +              node = component->find_operation(DEG_OPCODE_VIEW_LAYER_INIT);
 +      }
 +      else if (id_type == ID_OB) {
 +              component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS);
 +              if (component == NULL) {
 +                      return;
 +              }
 +              node = component->find_operation(DEG_OPCODE_OBJECT_BASE_FLAGS);
 +              if (node == NULL) {
 +                      return;
 +              }
 +      }
 +      if (node != NULL) {
 +              node->tag_update(graph);
 +      }
  }
  
 -void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
 +void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id)
  {
 -      if (id == NULL) {
 -              /* Ideally should not happen, but old depsgraph allowed this. */
 +      /* NOTE: We handle this immediately, without delaying anything, to be
 +       * sure we don't cause threading issues with OpenGL.
 +       */
 +      /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */
 +      DEGEditorUpdateContext update_ctx = {NULL};
 +      update_ctx.bmain = bmain;
 +      update_ctx.scene = graph->scene;
 +      update_ctx.view_layer = graph->view_layer;
 +      deg_editors_id_update(&update_ctx, id);
 +}
 +
 +void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag)
 +{
 +      bNodeTree *ntree = NULL;
 +      switch (GS(id->name)) {
 +              case ID_MA:
 +                      ntree = ((Material *)id)->nodetree;
 +                      break;
 +              default:
 +                      break;
 +      }
 +      if (ntree == NULL) {
                return;
        }
 -      DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag);
 +      IDDepsNode *id_node = graph->find_id_node(&ntree->id);
 +      if (id_node != NULL) {
 +              deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag);
 +      }
 +}
 +
 +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag)
 +{
 +      Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
 +      IDDepsNode *id_node = deg_graph->find_id_node(id);
 +      /* Make sure legacy flags are all nicely update. */
        lib_id_recalc_tag_flag(bmain, id, flag);
 -      for (Scene *scene = (Scene *)bmain->scene.first;
 -           scene != NULL;
 -           scene = (Scene *)scene->id.next)
 -      {
 -              if (scene->depsgraph) {
 -                      Depsgraph *graph = scene->depsgraph;
 -                      if (flag == 0) {
 -                              /* TODO(sergey): Currently blender is still tagging IDs
 -                               * for recalc just using flag=0. This isn't totally correct
 -                               * but we'd better deal with such cases and don't fail.
 -                               */
 -                              DEG_graph_id_tag_update(bmain, graph, id);
 -                              continue;
 -                      }
 -                      if (flag & OB_RECALC_DATA && GS(id->name) == ID_OB) {
 -                              Object *object = (Object *)id;
 -                              if (object->data != NULL) {
 -                                      DEG_graph_id_tag_update(bmain,
 -                                                              graph,
 -                                                              (ID *)object->data);
 +      if (id_node == NULL) {
 +              /* Shouldn't happen, but better be sure here. */
 +              return;
 +      }
 +      /* Tag components based on flags. */
 +      if (flag == 0) {
 +              id_tag_update_special_zero_flag(graph, id_node);
 +              id_tag_update_ntree_special(bmain, graph, id, flag);
 +              return;
 +      }
 +      if (flag & OB_RECALC_OB) {
 +              id_tag_update_object_transform(graph, id_node);
 +      }
 +      if (flag & OB_RECALC_DATA) {
 +              id_tag_update_object_data(graph, id_node);
 +              if (DEG_depsgraph_use_copy_on_write()) {
 +                      if (flag & DEG_TAG_COPY_ON_WRITE) {
 +                              const ID_Type id_type = GS(id_node->id_orig->name);
 +                              if (id_type == ID_OB) {
 +                                      Object *object = (Object *)id_node->id_orig;
 +                                      ID *ob_data = (ID *)object->data;
 +                                      DEG_id_tag_update_ex(bmain, ob_data, flag);
                                }
                        }
 -                      if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) {
 -                              DEG_graph_id_tag_update(bmain, graph, id);
 -                      }
 -                      else if (flag & OB_RECALC_TIME) {
 -                              DEG_graph_id_tag_update(bmain, graph, id);
 +              }
 +      }
 +      if (flag & OB_RECALC_TIME) {
 +              id_tag_update_object_time(graph, id_node);
 +      }
 +      if (flag & PSYS_RECALC) {
 +              id_tag_update_particle(graph, id_node, flag);
 +      }
 +      if (flag & DEG_TAG_SHADING_UPDATE) {
 +              id_tag_update_shading(graph, id_node);
 +      }
 +      if (flag & DEG_TAG_COPY_ON_WRITE) {
 +              id_tag_update_copy_on_write(graph, id_node);
 +      }
 +      if (flag & DEG_TAG_SELECT_UPDATE) {
 +              id_tag_update_select_update(graph, id_node);
 +      }
 +      if (flag & DEG_TAG_BASE_FLAGS_UPDATE) {
 +              id_tag_update_base_flags(graph, id_node);
 +      }
 +      if (flag & DEG_TAG_EDITORS_UPDATE) {
 +              id_tag_update_editors_update(bmain, graph, id);
 +      }
 +      id_tag_update_ntree_special(bmain, graph, id, flag);
 +}
 +
 +void deg_id_tag_update(Main *bmain, ID *id, int flag)
 +{
 +      lib_id_recalc_tag_flag(bmain, id, flag);
 +      LINKLIST_FOREACH(Scene *, scene, &bmain->scene) {
 +              LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
 +                      Depsgraph *depsgraph =
 +                              (Depsgraph *)BKE_scene_get_depsgraph(scene,
 +                                                                   view_layer,
 +                                                                   false);
 +                      if (depsgraph != NULL) {
 +                              deg_graph_id_tag_update(bmain, depsgraph, id, flag);
                        }
                }
        }
 +}
  
 -#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
 -      /* Special handling from the legacy depsgraph.
 -       * TODO(sergey): Need to get rid of those once all the areas
 -       * are re-formulated in terms of franular nodes.
 -       */
 -      depsgraph_legacy_handle_update_tag(bmain, id, flag);
 -#endif
 +void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph)
 +{
 +      /* Make sure objects are up to date. */
 +      foreach (DEG::IDDepsNode *id_node, graph->id_nodes) {
 +              const ID_Type id_type = GS(id_node->id_orig->name);
 +              int flag = 0;
 +              /* We only tag components which needs an update. Tagging everything is
 +               * not a good idea because that might reset particles cache (or any
 +               * other type of cache).
 +               *
 +               * TODO(sergey): Need to generalize this somehow.
 +               */
 +              if (id_type == ID_OB) {
 +                      flag |= OB_RECALC_OB | OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE;
 +              }
 +              deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag);
 +      }
 +      /* Make sure collection properties are up to date. */
 +      for (Scene *scene_iter = graph->scene; scene_iter != NULL; scene_iter = scene_iter->set) {
 +              IDDepsNode *scene_id_node = graph->find_id_node(&scene_iter->id);
 +              BLI_assert(scene_id_node != NULL);
 +              scene_id_node->tag_update(graph);
 +      }
 +}
 +
 +}  /* namespace */
 +
 +}  // namespace DEG
 +
 +/* Tag given ID for an update in all the dependency graphs. */
 +void DEG_id_tag_update(ID *id, int flag)
 +{
 +      DEG_id_tag_update_ex(G.main, id, flag);
 +}
 +
 +void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag)
 +{
 +      if (id == NULL) {
 +              /* Ideally should not happen, but old depsgraph allowed this. */
 +              return;
 +      }
 +      DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag);
 +      DEG::deg_id_tag_update(bmain, id, flag);
 +}
 +
 +void DEG_graph_id_tag_update(struct Main *bmain,
 +                             struct Depsgraph *depsgraph,
 +                             struct ID *id,
 +                             int flag)
 +{
 +      DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph;
 +      DEG::deg_graph_id_tag_update(bmain, graph, id, flag);
  }
  
  /* Mark a particular datablock type as having changing. */
 -void DEG_id_type_tag(Main *bmain, short idtype)
 +void DEG_id_type_tag(Main *bmain, short id_type)
  {
 -      if (idtype == ID_NT) {
 +      if (id_type == ID_NT) {
                /* Stupid workaround so parent datablocks of nested nodetree get looped
                 * over when we loop over tagged datablock types.
                 */
                DEG_id_type_tag(bmain, ID_SCE);
        }
  
 -      bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
 +      bmain->id_tag_update[BKE_idcode_to_index(id_type)] = 1;
  }
  
 -/* Recursively push updates out to all nodes dependent on this,
 - * until all affected are tagged and/or scheduled up for eval
 - */
 -void DEG_ids_flush_tagged(Main *bmain)
 +void DEG_graph_flush_update(Main *bmain, Depsgraph *depsgraph)
  {
 -      for (Scene *scene = (Scene *)bmain->scene.first;
 -           scene != NULL;
 -           scene = (Scene *)scene->id.next)
 -      {
 -              DEG_scene_flush_update(bmain, scene);
 -      }
 -}
 -
 -void DEG_scene_flush_update(Main *bmain, Scene *scene)
 -{
 -      if (scene->depsgraph == NULL) {
 +      if (depsgraph == NULL) {
                return;
        }
 -      DEG::deg_graph_flush_updates(
 -              bmain,
 -              reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph));
 +      DEG::deg_graph_flush_updates(bmain, (DEG::Depsgraph *)depsgraph);
  }
  
  /* Update dependency graph when visible scenes/layers changes. */
 -void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
 +void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph)
  {
 -      DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
 -      wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
 -      int old_layers = graph->layers;
 -      if (wm != NULL) {
 -              BKE_main_id_tag_listbase(&bmain->scene, LIB_TAG_DOIT, true);
 -              graph->layers = 0;
 -              for (wmWindow *win = (wmWindow *)wm->windows.first;
 -                   win != NULL;
 -                   win = (wmWindow *)win->next)
 -              {
 -                      Scene *scene = win->screen->scene;
 -                      if (scene->id.tag & LIB_TAG_DOIT) {
 -                              graph->layers |= BKE_screen_visible_layers(win->screen, scene);
 -                              scene->id.tag &= ~LIB_TAG_DOIT;
 -                      }
 -              }
 -      }
 -      else {
 -              /* All the layers for background render for now. */
 -              graph->layers = (1 << 20) - 1;
 -      }
 -      if (old_layers != graph->layers) {
 -              /* Tag all objects which becomes visible (or which becomes needed for dependencies)
 -               * for recalc.
 -               *
 -               * This is mainly needed on file load only, after that updates of invisible objects
 -               * will be stored in the pending list.
 -               */
 -              GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
 -              {
 -                      ID *id = id_node->id;
 -                      if ((id->tag & LIB_TAG_ID_RECALC_ALL) != 0 ||
 -                          (id_node->layers & scene->lay_updated) == 0)
 -                      {
 -                              id_node->tag_update(graph);
 -                      }
 -                      /* A bit of magic: if object->recalc is set it means somebody tagged
 -                       * it for update. If corresponding ID recalc flags are zero it means
 -                       * graph has been evaluated after that and the recalc was skipped
 -                       * because of visibility check.
 -                       */
 -                      if (GS(id->name) == ID_OB) {
 -                              Object *object = (Object *)id;
 -                              if ((id->tag & LIB_TAG_ID_RECALC_ALL) == 0 &&
 -                                  (object->recalc & OB_RECALC_ALL) != 0)
 -                              {
 -                                      id_node->tag_update(graph);
 -                                      DEG::ComponentDepsNode *anim_comp =
 -                                              id_node->find_component(DEG::DEG_NODE_TYPE_ANIMATION);
 -                                      if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
 -                                              anim_comp->tag_update(graph);
 -                                      }
 -                              }
 -                      }
 -              }
 -              GHASH_FOREACH_END();
 -      }
 -      scene->lay_updated |= graph->layers;
 -      /* If graph is tagged for update, we don't need to bother with updates here,
 -       * nodes will be re-created.
 -       */
 -      if (graph->need_update) {
 -              return;
 -      }
 -      /* Special trick to get local view to work.  */
 -      LINKLIST_FOREACH (Base *, base, &scene->base) {
 -              Object *object = base->object;
 -              DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
 -              id_node->layers = 0;
 -      }
 -      LINKLIST_FOREACH (Base *, base, &scene->base) {
 -              Object *object = base->object;
 -              DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
 -              id_node->layers |= base->lay;
 -              if (object == scene->camera) {
 -                      /* Camera should always be updated, it used directly by viewport. */
 -                      id_node->layers |= (unsigned int)(-1);
 -              }
 -      }
 -      DEG::deg_graph_build_flush_layers(graph);
 -      LINKLIST_FOREACH (Base *, base, &scene->base) {
 -              Object *object = base->object;
 -              DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
 -              GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp, id_node->components)
 -              {
 -                      id_node->layers |= comp->layers;
 -              }
 -              GHASH_FOREACH_END();
 -      }
 +      DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph;
 +      DEG::deg_graph_on_visible_update(bmain, graph);
  }
  
  void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
  {
 -      for (Scene *scene = (Scene *)bmain->scene.first;
 -           scene != NULL;
 -           scene = (Scene *)scene->id.next)
 -      {
 -              if (scene->depsgraph != NULL) {
 -                      DEG_graph_on_visible_update(bmain, scene);
 +      LINKLIST_FOREACH(Scene *, scene, &bmain->scene) {
 +              LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
 +                      Depsgraph *depsgraph =
 +                              (Depsgraph *)BKE_scene_get_depsgraph(scene,
 +                                                                   view_layer,
 +                                                                   false);
 +                      if (depsgraph != NULL) {
 +                              DEG_graph_on_visible_update(bmain, depsgraph);
 +                      }
                }
        }
  }
  /* Check if something was changed in the database and inform
   * editors about this.
   */
 -void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
 +void DEG_ids_check_recalc(Main *bmain,
 +                          Scene *scene,
 +                          ViewLayer *view_layer,
 +                          bool time)
  {
        ListBase *lbarray[MAX_LIBARRAY];
        int a;
                }
        }
  
 -      DEG::deg_editors_scene_update(bmain, scene, (updated || time));
 +      DEGEditorUpdateContext update_ctx = {NULL};
 +      update_ctx.bmain = bmain;
 +      update_ctx.scene = scene;
 +      update_ctx.view_layer = view_layer;
 +      DEG::deg_editors_scene_update(&update_ctx, (updated || time));
  }
  
  void DEG_ids_clear_recalc(Main *bmain)
  
                if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
                        for (; id; id = (ID *)id->next) {
-                               id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
+                               id->tag &= ~LIB_TAG_ID_RECALC_ALL;
  
                                /* Some ID's contain semi-datablock nodetree */
                                ntree = ntreeFromID(id);
                                if (ntree != NULL) {
-                                       ntree->id.tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
+                                       ntree->id.tag &= ~LIB_TAG_ID_RECALC_ALL;
                                }
                        }
                }