Merge branch 'blender2.7'
[blender.git] / intern / cycles / blender / blender_session.cpp
index dfa92dd..c634926 100644 (file)
@@ -53,23 +53,25 @@ int BlenderSession::end_resumable_chunk = 0;
 bool BlenderSession::print_render_stats = false;
 
 BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
-                               BL::UserPreferences& b_userpref,
+                               BL::Preferences& b_userpref,
                                BL::BlendData& b_data,
-                               BL::Scene& b_scene)
-: b_engine(b_engine),
+                               bool preview_osl)
+: session(NULL),
+  sync(NULL),
+  b_engine(b_engine),
   b_userpref(b_userpref),
   b_data(b_data),
   b_render(b_engine.render()),
-  b_scene(b_scene),
+  b_depsgraph(PointerRNA_NULL),
+  b_scene(PointerRNA_NULL),
   b_v3d(PointerRNA_NULL),
   b_rv3d(PointerRNA_NULL),
+  width(0),
+  height(0),
+  preview_osl(preview_osl),
   python_thread_state(NULL)
 {
        /* offline render */
-
-       width = render_resolution_x(b_render);
-       height = render_resolution_y(b_render);
-
        background = true;
        last_redraw_time = 0.0;
        start_resize_time = 0.0;
@@ -77,25 +79,27 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
 }
 
 BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
-                               BL::UserPreferences& b_userpref,
+                               BL::Preferences& b_userpref,
                                BL::BlendData& b_data,
-                               BL::Scene& b_scene,
                                BL::SpaceView3D& b_v3d,
                                BL::RegionView3D& b_rv3d,
                                int width, int height)
-: b_engine(b_engine),
+: session(NULL),
+  sync(NULL),
+  b_engine(b_engine),
   b_userpref(b_userpref),
   b_data(b_data),
-  b_render(b_scene.render()),
-  b_scene(b_scene),
+  b_render(b_engine.render()),
+  b_depsgraph(PointerRNA_NULL),
+  b_scene(PointerRNA_NULL),
   b_v3d(b_v3d),
   b_rv3d(b_rv3d),
   width(width),
   height(height),
+  preview_osl(false),
   python_thread_state(NULL)
 {
        /* 3d view render */
-
        background = false;
        last_redraw_time = 0.0;
        start_resize_time = 0.0;
@@ -133,6 +137,7 @@ void BlenderSession::create_session()
 
        /* create scene */
        scene = new Scene(scene_params, session->device);
+       scene->name = b_scene.name();
 
        /* setup callbacks for builtin image support */
        scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3);
@@ -141,26 +146,19 @@ void BlenderSession::create_session()
 
        session->scene = scene;
 
+       /* There is no single depsgraph to use for the entire render.
+        * So we need to handle this differently.
+        *
+        * We could loop over the final render result render layers in pipeline and keep Cycles unaware of multiple layers,
+        * or perhaps move syncing further down in the pipeline.
+        */
        /* create sync */
        sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
        BL::Object b_camera_override(b_engine.camera_override());
        if(b_v3d) {
-               if(session_pause == false) {
-                       /* full data sync */
-                       sync->sync_view(b_v3d, b_rv3d, width, height);
-                       sync->sync_data(b_render,
-                                       b_v3d,
-                                       b_camera_override,
-                                       width, height,
-                                       &python_thread_state,
-                                       b_rlay_name.c_str());
-               }
+               sync->sync_view(b_v3d, b_rv3d, width, height);
        }
        else {
-               /* for final render we will do full data sync per render layer, only
-                * do some basic syncing here, no objects or materials for speed */
-               sync->sync_render_layers(b_v3d, NULL);
-               sync->sync_integrator();
                sync->sync_camera(b_render, b_camera_override, width, height, "");
        }
 
@@ -173,18 +171,40 @@ void BlenderSession::create_session()
        update_resumable_tile_manager(session_params.samples);
 }
 
-void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_)
+void BlenderSession::reset_session(BL::BlendData& b_data, BL::Depsgraph& b_depsgraph)
 {
-       b_data = b_data_;
-       b_render = b_engine.render();
-       b_scene = b_scene_;
+       this->b_data = b_data;
+       this->b_depsgraph = b_depsgraph;
+       this->b_scene = b_depsgraph.scene_eval();
+
+       if(preview_osl) {
+               PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+               RNA_boolean_set(&cscene, "shading_system", preview_osl);
+       }
+
+       if(b_v3d) {
+               this->b_render = b_scene.render();
+       }
+       else {
+               this->b_render = b_engine.render();
+               width = render_resolution_x(b_render);
+               height = render_resolution_y(b_render);
+       }
+
+       if(session == NULL) {
+               create();
+       }
+
+       if(b_v3d) {
+               /* NOTE: We need to create session, but all the code from below
+                * will make viewport render to stuck on initialization.
+                */
+               return;
+       }
 
        SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
        SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
 
-       width = render_resolution_x(b_render);
-       height = render_resolution_y(b_render);
-
        if(scene->params.modified(scene_params) ||
           session->params.modified(session_params) ||
           !scene_params.persistent_data)
@@ -192,11 +212,8 @@ void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_)
                /* if scene or session parameters changed, it's easier to simply re-create
                 * them rather than trying to distinguish which settings need to be updated
                 */
-
-               delete session;
-
+               free_session();
                create_session();
-
                return;
        }
 
@@ -210,16 +227,12 @@ void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_)
         */
        session->stats.mem_peak = session->stats.mem_used;
 
+       /* There is no single depsgraph to use for the entire render.
+        * See note on create_session().
+        */
        /* sync object should be re-created */
        sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
 
-       /* for final render we will do full data sync per render layer, only
-        * do some basic syncing here, no objects or materials for speed */
-       BL::Object b_camera_override(b_engine.camera_override());
-       sync->sync_render_layers(b_v3d, NULL);
-       sync->sync_integrator();
-       sync->sync_camera(b_render, b_camera_override, width, height, "");
-
        BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
        BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
        BufferParams buffer_params = BlenderSync::get_buffer_params(b_render,
@@ -379,8 +392,10 @@ static void add_cryptomatte_layer(BL::RenderResult& b_rr, string name, string ma
        render_add_metadata(b_rr, prefix+"manifest", manifest);
 }
 
-void BlenderSession::render()
+void BlenderSession::render(BL::Depsgraph& b_depsgraph_)
 {
+       b_depsgraph = b_depsgraph_;
+
        /* set callback to write out render results */
        session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
        session->update_render_tile_cb = function_bind(&BlenderSession::update_render_tile, this, _1, _2);
@@ -390,126 +405,98 @@ void BlenderSession::render()
        BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
 
        /* render each layer */
-       BL::RenderSettings r = b_scene.render();
-       BL::RenderSettings::layers_iterator b_layer_iter;
-       BL::RenderResult::views_iterator b_view_iter;
+       BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
 
        /* We do some special meta attributes when we only have single layer. */
-       const bool is_single_layer = (r.layers.length() == 1);
+       const bool is_single_layer = (b_scene.view_layers.length() == 1);
 
-       for(r.layers.begin(b_layer_iter); b_layer_iter != r.layers.end(); ++b_layer_iter) {
-               b_rlay_name = b_layer_iter->name();
-
-               /* temporary render result to find needed passes and views */
-               BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str(), NULL);
-               BL::RenderResult::layers_iterator b_single_rlay;
-               b_rr.layers.begin(b_single_rlay);
-
-               /* layer will be missing if it was disabled in the UI */
-               if(b_single_rlay == b_rr.layers.end()) {
-                       end_render_result(b_engine, b_rr, true, true, false);
-                       continue;
-               }
-
-               BL::RenderLayer b_rlay = *b_single_rlay;
-
-               /* add passes */
-               vector<Pass> passes = sync->sync_render_passes(b_rlay, *b_layer_iter, session_params);
-               buffer_params.passes = passes;
-
-               PointerRNA crl = RNA_pointer_get(&b_layer_iter->ptr, "cycles");
-               bool use_denoising = get_boolean(crl, "use_denoising");
-               bool denoising_passes = use_denoising || get_boolean(crl, "denoising_store_passes");
-
-               session->tile_manager.schedule_denoising = use_denoising;
-               buffer_params.denoising_data_pass = denoising_passes;
-               buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES);
-
-               session->params.use_denoising = use_denoising;
-               session->params.denoising_passes = denoising_passes;
-               session->params.denoising_radius = get_int(crl, "denoising_radius");
-               session->params.denoising_strength = get_float(crl, "denoising_strength");
-               session->params.denoising_feature_strength = get_float(crl, "denoising_feature_strength");
-               session->params.denoising_relative_pca = get_boolean(crl, "denoising_relative_pca");
-
-               scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
-               scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass;
-               scene->film->pass_alpha_threshold = b_layer_iter->pass_alpha_threshold();
-               scene->film->tag_passes_update(scene, passes);
-               scene->film->tag_update(scene);
-               scene->integrator->tag_update(scene);
-
-               int view_index = 0;
-               for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) {
-                       b_rview_name = b_view_iter->name();
-
-                       /* set the current view */
-                       b_engine.active_view_set(b_rview_name.c_str());
-
-                       /* update scene */
-                       BL::Object b_camera_override(b_engine.camera_override());
-                       sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
-                       sync->sync_data(b_render,
-                                       b_v3d,
-                                       b_camera_override,
-                                       width, height,
-                                       &python_thread_state,
-                                       b_rlay_name.c_str());
-
-                       /* Make sure all views have different noise patterns. - hardcoded value just to make it random */
-                       if(view_index != 0) {
-                               scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef));
-                               scene->integrator->tag_update(scene);
-                       }
+       /* temporary render result to find needed passes and views */
+       BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_view_layer.name().c_str(), NULL);
+       BL::RenderResult::layers_iterator b_single_rlay;
+       b_rr.layers.begin(b_single_rlay);
+       BL::RenderLayer b_rlay = *b_single_rlay;
+       b_rlay_name = b_view_layer.name();
+
+       /* add passes */
+       vector<Pass> passes = sync->sync_render_passes(b_rlay, b_view_layer, session_params);
+       buffer_params.passes = passes;
+
+       PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
+       bool use_denoising = get_boolean(crl, "use_denoising");
+       bool denoising_passes = use_denoising || get_boolean(crl, "denoising_store_passes");
+
+       session->tile_manager.schedule_denoising = use_denoising;
+       buffer_params.denoising_data_pass = denoising_passes;
+       buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES);
+
+       session->params.use_denoising = use_denoising;
+       session->params.denoising_passes = denoising_passes;
+       session->params.denoising_radius = get_int(crl, "denoising_radius");
+       session->params.denoising_strength = get_float(crl, "denoising_strength");
+       session->params.denoising_feature_strength = get_float(crl, "denoising_feature_strength");
+       session->params.denoising_relative_pca = get_boolean(crl, "denoising_relative_pca");
+
+       scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
+       scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass;
+       session->params.denoising_radius = get_int(crl, "denoising_radius");
+       session->params.denoising_strength = get_float(crl, "denoising_strength");
+       session->params.denoising_feature_strength = get_float(crl, "denoising_feature_strength");
+       session->params.denoising_relative_pca = get_boolean(crl, "denoising_relative_pca");
+
+       scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold();
+       scene->film->tag_passes_update(scene, passes);
+       scene->film->tag_update(scene);
+       scene->integrator->tag_update(scene);
 
-                       /* Update number of samples per layer. */
-                       int samples = sync->get_layer_samples();
-                       bool bound_samples = sync->get_layer_bound_samples();
-                       int effective_layer_samples;
+       BL::RenderResult::views_iterator b_view_iter;
+       int view_index = 0;
+       for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) {
+               b_rview_name = b_view_iter->name();
 
-                       if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
-                               effective_layer_samples = samples;
-                       else
-                               effective_layer_samples = session_params.samples;
+               /* set the current view */
+               b_engine.active_view_set(b_rview_name.c_str());
 
-                       /* Update tile manager if we're doing resumable render. */
-                       update_resumable_tile_manager(effective_layer_samples);
+               /* update scene */
+               BL::Object b_camera_override(b_engine.camera_override());
+               sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
+               sync->sync_data(b_render,
+                               b_depsgraph,
+                               b_v3d,
+                               b_camera_override,
+                               width, height,
+                               &python_thread_state);
+               builtin_images_load();
+
+               /* Attempt to free all data which is held by Blender side, since at this
+                * point we knwo that we've got everything to render current view layer.
+                */
+               free_blender_memory_if_possible();
 
-                       /* Update session itself. */
-                       session->reset(buffer_params, effective_layer_samples);
+               /* Make sure all views have different noise patterns. - hardcoded value just to make it random */
+               if(view_index != 0) {
+                       scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef));
+                       scene->integrator->tag_update(scene);
+               }
 
-                       /* render */
-                       session->start();
-                       session->wait();
+               /* Update number of samples per layer. */
+               int samples = sync->get_layer_samples();
+               bool bound_samples = sync->get_layer_bound_samples();
+               int effective_layer_samples;
 
-                       if(session->progress.get_cancel())
-                               break;
-               }
+               if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
+                       effective_layer_samples = samples;
+               else
+                       effective_layer_samples = session_params.samples;
 
-               BL::RenderResult b_full_rr = b_engine.get_result();
-               if(is_single_layer) {
-                       string num_aa_samples = string_printf("%d", session->params.samples);
-                       render_add_metadata(b_full_rr, "Cycles Samples", num_aa_samples);
-                       /* TODO(sergey): Report whether we're doing resumable render
-                        * and also start/end sample if so.
-                        */
-               }
+               /* Update tile manager if we're doing resumable render. */
+               update_resumable_tile_manager(effective_layer_samples);
 
-               if(scene->film->cryptomatte_passes & CRYPT_OBJECT) {
-                       add_cryptomatte_layer(b_full_rr, b_rlay_name+".CryptoObject",
-                                             scene->object_manager->get_cryptomatte_objects(scene));
-               }
-               if(scene->film->cryptomatte_passes & CRYPT_MATERIAL) {
-                       add_cryptomatte_layer(b_full_rr, b_rlay_name+".CryptoMaterial",
-                                             scene->shader_manager->get_cryptomatte_materials(scene));
-               }
-               if(scene->film->cryptomatte_passes & CRYPT_ASSET) {
-                       add_cryptomatte_layer(b_full_rr, b_rlay_name+".CryptoAsset",
-                                             scene->object_manager->get_cryptomatte_assets(scene));
-               }
+               /* Update session itself. */
+               session->reset(buffer_params, effective_layer_samples);
 
-               /* free result without merging */
-               end_render_result(b_engine, b_rr, true, true, false);
+               /* render */
+               session->start();
+               session->wait();
 
                if(!b_engine.is_preview() && background && print_render_stats) {
                        RenderStats stats;
@@ -521,6 +508,32 @@ void BlenderSession::render()
                        break;
        }
 
+       if(is_single_layer) {
+               BL::RenderResult b_rr = b_engine.get_result();
+               string num_aa_samples = string_printf("%d", session->params.samples);
+               b_rr.stamp_data_add_field("Cycles Samples", num_aa_samples.c_str());
+               /* TODO(sergey): Report whether we're doing resumable render
+                * and also start/end sample if so.
+                */
+       }
+
+       /* Write cryptomatte metadata. */
+       if(scene->film->cryptomatte_passes & CRYPT_OBJECT) {
+               add_cryptomatte_layer(b_rr, b_rlay_name+".CryptoObject",
+                                                         scene->object_manager->get_cryptomatte_objects(scene));
+       }
+       if(scene->film->cryptomatte_passes & CRYPT_MATERIAL) {
+               add_cryptomatte_layer(b_rr, b_rlay_name+".CryptoMaterial",
+                                                         scene->shader_manager->get_cryptomatte_materials(scene));
+       }
+       if(scene->film->cryptomatte_passes & CRYPT_ASSET) {
+               add_cryptomatte_layer(b_rr, b_rlay_name+".CryptoAsset",
+                                                         scene->object_manager->get_cryptomatte_assets(scene));
+       }
+
+       /* free result without merging */
+       end_render_result(b_engine, b_rr, true, true, false);
+
        double total_time, render_time;
        session->progress.get_time(total_time, render_time);
        VLOG(1) << "Total render time: " << total_time;
@@ -530,6 +543,8 @@ void BlenderSession::render()
        session->write_render_tile_cb = function_null;
        session->update_render_tile_cb = function_null;
 
+       /* TODO: find a way to clear this data for persistent data render */
+#if 0
        /* free all memory used (host and device), so we wouldn't leave render
         * engine with extra memory allocated
         */
@@ -538,6 +553,7 @@ void BlenderSession::render()
 
        delete sync;
        sync = NULL;
+#endif
 }
 
 static void populate_bake_data(BakeData *data, const
@@ -586,7 +602,8 @@ static int bake_pass_filter_get(const int pass_filter)
        return flag;
 }
 
-void BlenderSession::bake(BL::Object& b_object,
+void BlenderSession::bake(BL::Depsgraph& b_depsgraph_,
+                          BL::Object& b_object,
                           const string& pass_type,
                           const int pass_filter,
                           const int object_id,
@@ -595,6 +612,8 @@ void BlenderSession::bake(BL::Object& b_object,
                           const int /*depth*/,
                           float result[])
 {
+       b_depsgraph = b_depsgraph_;
+
        ShaderEvalType shader_type = get_shader_type(pass_type);
 
        /* Set baking flag in advance, so kernel loading can check if we need
@@ -627,11 +646,12 @@ void BlenderSession::bake(BL::Object& b_object,
                BL::Object b_camera_override(b_engine.camera_override());
                sync->sync_camera(b_render, b_camera_override, width, height, "");
                sync->sync_data(b_render,
-                                               b_v3d,
-                                               b_camera_override,
-                                               width, height,
-                                               &python_thread_state,
-                                               b_rlay_name.c_str());
+                               b_depsgraph,
+                               b_v3d,
+                               b_camera_override,
+                               width, height,
+                               &python_thread_state);
+               builtin_images_load();
        }
 
        BakeData *bake_data = NULL;
@@ -765,7 +785,7 @@ void BlenderSession::update_render_result(BL::RenderResult& b_rr,
        do_write_update_render_result(b_rr, b_rlay, rtile, true);
 }
 
-void BlenderSession::synchronize()
+void BlenderSession::synchronize(BL::Depsgraph& b_depsgraph_)
 {
        /* only used for viewport render */
        if(!b_v3d)
@@ -790,7 +810,7 @@ void BlenderSession::synchronize()
 
        /* copy recalc flags, outside of mutex so we can decide to do the real
         * synchronization at a later time to not block on running updates */
-       sync->sync_recalc();
+       sync->sync_recalc(b_depsgraph_);
 
        /* don't do synchronization if on pause */
        if(session_pause) {
@@ -805,19 +825,23 @@ void BlenderSession::synchronize()
        }
 
        /* data and camera synchronize */
+       b_depsgraph = b_depsgraph_;
+
        BL::Object b_camera_override(b_engine.camera_override());
        sync->sync_data(b_render,
+                       b_depsgraph,
                        b_v3d,
                        b_camera_override,
                        width, height,
-                       &python_thread_state,
-                       b_rlay_name.c_str());
+                       &python_thread_state);
 
        if(b_rv3d)
                sync->sync_view(b_v3d, b_rv3d, width, height);
        else
                sync->sync_camera(b_render, b_camera_override, width, height, "");
 
+       builtin_images_load();
+
        /* unlock */
        session->scene->mutex.unlock();
 
@@ -934,7 +958,7 @@ void BlenderSession::update_bake_progress()
 void BlenderSession::update_status_progress()
 {
        string timestatus, status, substatus;
-       string scene = "";
+       string scene_status = "";
        float progress;
        double total_time, remaining_time = 0, render_time;
        char time_str[128];
@@ -948,35 +972,31 @@ void BlenderSession::update_status_progress()
                remaining_time = (1.0 - (double)progress) * (render_time / (double)progress);
 
        if(background) {
-               scene += " | " + b_scene.name();
+               scene_status += " | " + scene->name;
                if(b_rlay_name != "")
-                       scene += ", "  + b_rlay_name;
+                       scene_status += ", "  + b_rlay_name;
 
                if(b_rview_name != "")
-                       scene += ", " + b_rview_name;
-       }
-       else {
-               BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), total_time);
-               timestatus = "Time:" + string(time_str) + " | ";
-       }
+                       scene_status += ", " + b_rview_name;
 
-       if(remaining_time > 0) {
-               BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), remaining_time);
-               timestatus += "Remaining:" + string(time_str) + " | ";
-       }
+               if(remaining_time > 0) {
+                       BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), remaining_time);
+                       timestatus += "Remaining:" + string(time_str) + " | ";
+               }
 
-       timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak);
+               timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak);
 
-       if(status.size() > 0)
-               status = " | " + status;
-       if(substatus.size() > 0)
-               status += " | " + substatus;
+               if(status.size() > 0)
+                       status = " | " + status;
+               if(substatus.size() > 0)
+                       status += " | " + substatus;
+       }
 
        double current_time = time_dt();
        /* When rendering in a window, redraw the status at least once per second to keep the elapsed and remaining time up-to-date.
         * For headless rendering, only report when something significant changes to keep the console output readable. */
        if(status != last_status || (!headless && (current_time - last_status_time) > 1.0)) {
-               b_engine.update_stats("", (timestatus + scene + status).c_str());
+               b_engine.update_stats("", (timestatus + scene_status + status).c_str());
                b_engine.update_memory_stats(mem_used, mem_peak);
                last_status = status;
                last_status_time = current_time;
@@ -1329,6 +1349,9 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
                fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
        }
        else {
+               /* We originally were passing view_layer here but in reality we need a
+                * a depsgraph to pass to the RE_point_density_minmax() function.
+                */
                /* TODO(sergey): Check we're indeed in shader node tree. */
                PointerRNA ptr;
                RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
@@ -1336,14 +1359,23 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
                if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
                        BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
                        int length;
-                       int settings = background ? 1 : 0;  /* 1 - render settings, 0 - vewport settings. */
-                       b_point_density_node.calc_point_density(b_scene, settings, &length, &pixels);
+                       b_point_density_node.calc_point_density(b_depsgraph, &length, &pixels);
                }
        }
 
        return false;
 }
 
+void BlenderSession::builtin_images_load()
+{
+       /* Force builtin images to be loaded along with Blender data sync. This
+        * is needed because we may be reading from depsgraph evaluated data which
+        * can be freed by Blender before Cycles reads it. */
+       ImageManager *manager = session->scene->image_manager;
+       Device *device = session->device;
+       manager->device_load_builtin(device, session->scene, session->progress);
+}
+
 void BlenderSession::update_resumable_tile_manager(int num_samples)
 {
        const int num_resumable_chunks = BlenderSession::num_resumable_chunks,
@@ -1381,4 +1413,16 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
        session->tile_manager.range_num_samples = range_num_samples;
 }
 
+void BlenderSession::free_blender_memory_if_possible()
+{
+       if(!background) {
+               /* During interactive render we can not free anything: attempts to save
+                * memory would cause things to be allocated and evaluated for every
+                * updated sample.
+                */
+               return;
+       }
+       b_engine.free_blender_memory();
+}
+
 CCL_NAMESPACE_END