Merge branch 'master' into blender2.8
[blender.git] / intern / cycles / blender / blender_session.cpp
index 00d23b9..eec13d0 100644 (file)
@@ -52,21 +52,22 @@ int BlenderSession::end_resumable_chunk = 0;
 BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
                                BL::UserPreferences& b_userpref,
                                BL::BlendData& b_data,
-                               BL::Scene& b_scene)
-: b_engine(b_engine),
+                               bool preview_osl)
+: session(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;
@@ -76,23 +77,24 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
 BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
                                BL::UserPreferences& 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),
+  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;
@@ -141,26 +143,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 +168,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)
@@ -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,
@@ -368,8 +381,10 @@ void BlenderSession::update_render_tile(RenderTile& rtile, bool highlight)
                do_write_update_render_tile(rtile, false, false);
 }
 
-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);
@@ -379,123 +394,110 @@ 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);
-
-       for(r.layers.begin(b_layer_iter); b_layer_iter != r.layers.end(); ++b_layer_iter) {
-               b_rlay_name = b_layer_iter->name();
+       const bool is_single_layer = (b_scene.view_layers.length() == 1);
 
-               /* 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);
+       /* 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;
 
-               /* 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;
-               }
+       /* add passes */
+       array<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");
+       buffer_params.denoising_data_pass = use_denoising;
+       session->tile_manager.schedule_denoising = use_denoising;
+       session->params.use_denoising = use_denoising;
+       scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
+       scene->film->denoising_flags = 0;
+       if(!get_boolean(crl, "denoising_diffuse_direct"))        scene->film->denoising_flags |= DENOISING_CLEAN_DIFFUSE_DIR;
+       if(!get_boolean(crl, "denoising_diffuse_indirect"))      scene->film->denoising_flags |= DENOISING_CLEAN_DIFFUSE_IND;
+       if(!get_boolean(crl, "denoising_glossy_direct"))         scene->film->denoising_flags |= DENOISING_CLEAN_GLOSSY_DIR;
+       if(!get_boolean(crl, "denoising_glossy_indirect"))       scene->film->denoising_flags |= DENOISING_CLEAN_GLOSSY_IND;
+       if(!get_boolean(crl, "denoising_transmission_direct"))   scene->film->denoising_flags |= DENOISING_CLEAN_TRANSMISSION_DIR;
+       if(!get_boolean(crl, "denoising_transmission_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_TRANSMISSION_IND;
+       if(!get_boolean(crl, "denoising_subsurface_direct"))     scene->film->denoising_flags |= DENOISING_CLEAN_SUBSURFACE_DIR;
+       if(!get_boolean(crl, "denoising_subsurface_indirect"))   scene->film->denoising_flags |= DENOISING_CLEAN_SUBSURFACE_IND;
+       scene->film->denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES);
+       buffer_params.denoising_clean_pass = scene->film->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);
 
-               BL::RenderLayer b_rlay = *b_single_rlay;
-
-               /* add passes */
-               array<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");
-               buffer_params.denoising_data_pass = use_denoising;
-               session->tile_manager.schedule_denoising = use_denoising;
-               session->params.use_denoising = use_denoising;
-               scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
-               scene->film->denoising_flags = 0;
-               if(!get_boolean(crl, "denoising_diffuse_direct"))        scene->film->denoising_flags |= DENOISING_CLEAN_DIFFUSE_DIR;
-               if(!get_boolean(crl, "denoising_diffuse_indirect"))      scene->film->denoising_flags |= DENOISING_CLEAN_DIFFUSE_IND;
-               if(!get_boolean(crl, "denoising_glossy_direct"))         scene->film->denoising_flags |= DENOISING_CLEAN_GLOSSY_DIR;
-               if(!get_boolean(crl, "denoising_glossy_indirect"))       scene->film->denoising_flags |= DENOISING_CLEAN_GLOSSY_IND;
-               if(!get_boolean(crl, "denoising_transmission_direct"))   scene->film->denoising_flags |= DENOISING_CLEAN_TRANSMISSION_DIR;
-               if(!get_boolean(crl, "denoising_transmission_indirect")) scene->film->denoising_flags |= DENOISING_CLEAN_TRANSMISSION_IND;
-               if(!get_boolean(crl, "denoising_subsurface_direct"))     scene->film->denoising_flags |= DENOISING_CLEAN_SUBSURFACE_DIR;
-               if(!get_boolean(crl, "denoising_subsurface_indirect"))   scene->film->denoising_flags |= DENOISING_CLEAN_SUBSURFACE_IND;
-               scene->film->denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES);
-               buffer_params.denoising_clean_pass = scene->film->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_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);
-                       }
+       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_rlay_name = b_view_layer.name();
+               b_rview_name = b_view_iter->name();
 
-                       /* Update number of samples per layer. */
-                       int samples = sync->get_layer_samples();
-                       bool bound_samples = sync->get_layer_bound_samples();
-                       int effective_layer_samples;
+               /* set the current view */
+               b_engine.active_view_set(b_rview_name.c_str());
 
-                       if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
-                               effective_layer_samples = samples;
-                       else
-                               effective_layer_samples = session_params.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();
 
-                       /* Update tile manager if we're doing resumable render. */
-                       update_resumable_tile_manager(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);
+               }
 
-                       /* Update session itself. */
-                       session->reset(buffer_params, effective_layer_samples);
+               /* Update number of samples per layer. */
+               int samples = sync->get_layer_samples();
+               bool bound_samples = sync->get_layer_bound_samples();
+               int effective_layer_samples;
 
-                       /* render */
-                       session->start();
-                       session->wait();
+               if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
+                       effective_layer_samples = samples;
+               else
+                       effective_layer_samples = session_params.samples;
 
-                       if(session->progress.get_cancel())
-                               break;
-               }
+               /* Update tile manager if we're doing resumable render. */
+               update_resumable_tile_manager(effective_layer_samples);
 
-               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.
-                        */
-               }
+               /* 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(session->progress.get_cancel())
                        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.
+                */
+       }
+
+       /* 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;
@@ -505,6 +507,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
         */
@@ -513,6 +517,7 @@ void BlenderSession::render()
 
        delete sync;
        sync = NULL;
+#endif
 }
 
 static void populate_bake_data(BakeData *data, const
@@ -561,7 +566,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,
@@ -570,6 +576,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
@@ -602,11 +610,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_depsgraph,
                                                b_v3d,
                                                b_camera_override,
                                                width, height,
-                                               &python_thread_state,
-                                               b_rlay_name.c_str());
+                                               &python_thread_state);
+               builtin_images_load();
        }
 
        BakeData *bake_data = NULL;
@@ -740,7 +749,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)
@@ -766,7 +775,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) {
@@ -781,19 +790,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();
 
@@ -1301,6 +1314,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);
@@ -1308,14 +1324,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,