diff options
Diffstat (limited to 'intern/cycles/blender/blender_session.cpp')
-rw-r--r-- | intern/cycles/blender/blender_session.cpp | 484 |
1 files changed, 285 insertions, 199 deletions
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 27541800804..f1cdda5cb13 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -30,6 +30,7 @@ #include "render/shader.h" #include "render/stats.h" +#include "util/util_algorithm.h" #include "util/util_color.h" #include "util/util_foreach.h" #include "util/util_function.h" @@ -53,23 +54,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 +80,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 +138,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 +147,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 +172,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 +213,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 +228,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,12 +393,25 @@ static void add_cryptomatte_layer(BL::RenderResult& b_rr, string name, string ma render_add_metadata(b_rr, prefix+"manifest", manifest); } -void BlenderSession::stamp_view_layer_metadata_do(const string& prefix) +/* TODO(sergey): Ideally this will be an utility function in util string.h, but + * currently is relying on Blender side function, so can not do that. */ +static string make_human_readable_time(double time) +{ + char time_str[128]; + BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), time); + return time_str; +} + +void BlenderSession::stamp_view_layer_metadata(Scene *scene, const string& view_layer_name) { BL::RenderResult b_rr = b_engine.get_result(); + string prefix = "cycles." + view_layer_name + "."; + /* Configured number of samples for the view layer. */ - b_rr.stamp_data_add_field((prefix + "samples").c_str(), - to_string(session->params.samples).c_str()); + b_rr.stamp_data_add_field( + (prefix + "samples").c_str(), + to_string(session->params.samples).c_str()); + /* Store ranged samples information. */ if(session->tile_manager.range_num_samples != -1) { b_rr.stamp_data_add_field( @@ -394,15 +421,36 @@ void BlenderSession::stamp_view_layer_metadata_do(const string& prefix) (prefix + "range_num_samples").c_str(), to_string(session->tile_manager.range_num_samples).c_str()); } -} -void BlenderSession::stamp_view_layer_metadata(const string& view_layer_name) -{ - stamp_view_layer_metadata_do("cycles." + view_layer_name + "."); + /* Write cryptomatte metadata. */ + if(scene->film->cryptomatte_passes & CRYPT_OBJECT) { + add_cryptomatte_layer(b_rr, view_layer_name + ".CryptoObject", + scene->object_manager->get_cryptomatte_objects(scene)); + } + if(scene->film->cryptomatte_passes & CRYPT_MATERIAL) { + add_cryptomatte_layer(b_rr, view_layer_name + ".CryptoMaterial", + scene->shader_manager->get_cryptomatte_materials(scene)); + } + if(scene->film->cryptomatte_passes & CRYPT_ASSET) { + add_cryptomatte_layer(b_rr, view_layer_name + ".CryptoAsset", + scene->object_manager->get_cryptomatte_assets(scene)); + } + + /* Store synchronization and bare-render times. */ + double total_time, render_time; + session->progress.get_time(total_time, render_time); + b_rr.stamp_data_add_field((prefix + "total_time").c_str(), + make_human_readable_time(total_time).c_str()); + b_rr.stamp_data_add_field((prefix + "render_time").c_str(), + make_human_readable_time(render_time).c_str()); + b_rr.stamp_data_add_field((prefix + "synchronization_time").c_str(), + make_human_readable_time(total_time - render_time).c_str()); } -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); @@ -412,122 +460,107 @@ 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(); - 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_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(); - /* 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); + /* add passes */ + vector<Pass> passes = sync->sync_render_passes(b_rlay, b_view_layer, session_params); + buffer_params.passes = passes; - /* 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; - } + PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); + bool full_denoising = get_boolean(crl, "use_denoising"); + bool write_denoising_passes = get_boolean(crl, "denoising_store_passes"); - 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 full_denoising = get_boolean(crl, "use_denoising"); - bool write_denoising_passes = get_boolean(crl, "denoising_store_passes"); - - bool run_denoising = full_denoising || write_denoising_passes; - - session->tile_manager.schedule_denoising = run_denoising; - buffer_params.denoising_data_pass = run_denoising; - buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); - buffer_params.denoising_prefiltered_pass = write_denoising_passes; - - session->params.run_denoising = run_denoising; - session->params.full_denoising = full_denoising; - session->params.write_denoising_passes = write_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->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_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); - } + bool run_denoising = full_denoising || write_denoising_passes; - /* Update number of samples per layer. */ - int samples = sync->get_layer_samples(); - bool bound_samples = sync->get_layer_bound_samples(); - int effective_layer_samples; + session->tile_manager.schedule_denoising = run_denoising; + buffer_params.denoising_data_pass = run_denoising; + buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); + buffer_params.denoising_prefiltered_pass = write_denoising_passes; - if(samples != 0 && (!bound_samples || (samples < session_params.samples))) - effective_layer_samples = samples; - else - effective_layer_samples = session_params.samples; + session->params.run_denoising = run_denoising; + session->params.full_denoising = full_denoising; + session->params.write_denoising_passes = write_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"); - /* Update tile manager if we're doing resumable render. */ - update_resumable_tile_manager(effective_layer_samples); + scene->film->denoising_data_pass = buffer_params.denoising_data_pass; + scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass; + scene->film->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_pass; - /* Update session itself. */ - session->reset(buffer_params, effective_layer_samples); + 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); - /* render */ - session->start(); - session->wait(); + BL::RenderResult::views_iterator b_view_iter; - if(session->progress.get_cancel()) - break; - } + int num_views = 0; + for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) { + num_views++; + } - stamp_view_layer_metadata(b_rlay_name); + 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(); - BL::RenderResult b_full_rr = b_engine.get_result(); - 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)); + /* 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_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. + */ + /* At the moment we only free if we are not doing multi-view (or if we are rendering the last view). + * See T58142/D4239 for discussion. + */ + if(view_index == num_views - 1) { + free_blender_memory_if_possible(); } - if(scene->film->cryptomatte_passes & CRYPT_ASSET) { - add_cryptomatte_layer(b_full_rr, b_rlay_name+".CryptoAsset", - scene->object_manager->get_cryptomatte_assets(scene)); + + /* 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); } - /* free result without merging */ - end_render_result(b_engine, b_rr, true, true, false); + /* 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(samples != 0 && (!bound_samples || (samples < session_params.samples))) + effective_layer_samples = samples; + else + effective_layer_samples = session_params.samples; + + /* Update tile manager if we're doing resumable render. */ + update_resumable_tile_manager(effective_layer_samples); + + /* Update session itself. */ + session->reset(buffer_params, effective_layer_samples); + + /* render */ + session->start(); + session->wait(); if(!b_engine.is_preview() && background && print_render_stats) { RenderStats stats; @@ -539,6 +572,12 @@ void BlenderSession::render() break; } + /* add metadata */ + stamp_view_layer_metadata(scene, b_rlay_name); + + /* 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; @@ -548,6 +587,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 */ @@ -556,6 +597,7 @@ void BlenderSession::render() delete sync; sync = NULL; +#endif } static void populate_bake_data(BakeData *data, const @@ -604,7 +646,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, @@ -613,6 +656,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 @@ -645,11 +690,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; @@ -678,10 +724,14 @@ void BlenderSession::bake(BL::Object& b_object, } } - int object = object_index; + /* Object might have been disabled for rendering or excluded in some + * other way, in that case Blender will report a warning afterwards. */ + if (object_index != OBJECT_NONE) { + int object = object_index; - bake_data = scene->bake_manager->init(object, tri_offset, num_pixels); - populate_bake_data(bake_data, object_id, pixel_array, num_pixels); + bake_data = scene->bake_manager->init(object, tri_offset, num_pixels); + populate_bake_data(bake_data, object_id, pixel_array, num_pixels); + } /* set number of samples */ session->tile_manager.set_samples(session_params.samples); @@ -692,7 +742,7 @@ void BlenderSession::bake(BL::Object& b_object, } /* Perform bake. Check cancel to avoid crash with incomplete scene data. */ - if(!session->progress.get_cancel()) { + if(!session->progress.get_cancel() && bake_data) { scene->bake_manager->bake(scene->device, &scene->dscene, scene, session->progress, shader_type, bake_pass_filter, bake_data, result); } @@ -783,7 +833,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) @@ -808,7 +858,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) { @@ -823,19 +873,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(); @@ -957,7 +1011,7 @@ void BlenderSession::update_bake_progress() void BlenderSession::update_status_progress() { string timestatus, status, substatus, kernel_status; - string scene = ""; + string scene_status = ""; float progress; double total_time, remaining_time = 0, render_time; char time_str[128]; @@ -972,37 +1026,33 @@ 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(kernel_status.size() > 0) - status += " | " + kernel_status; + if(status.size() > 0) + status = " | " + status; + if(substatus.size() > 0) + status += " | " + substatus; + if(kernel_status.size() > 0) + status += " | " + kernel_status; + } 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; @@ -1355,6 +1405,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); @@ -1362,14 +1415,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, @@ -1378,9 +1440,15 @@ void BlenderSession::update_resumable_tile_manager(int num_samples) return; } - const int num_samples_per_chunk = (int)ceilf((float)num_samples / num_resumable_chunks); + if (num_resumable_chunks > num_samples) { + fprintf(stderr, "Cycles warning: more sample chunks (%d) than samples (%d), " + "this will cause some samples to be included in multiple chunks.\n", + num_resumable_chunks, num_samples); + } + + const float num_samples_per_chunk = (float)num_samples / num_resumable_chunks; - int range_start_sample, range_num_samples; + float range_start_sample, range_num_samples; if(current_resumable_chunk != 0) { /* Single chunk rendering. */ range_start_sample = num_samples_per_chunk * (current_resumable_chunk - 1); @@ -1392,19 +1460,37 @@ void BlenderSession::update_resumable_tile_manager(int num_samples) range_start_sample = num_samples_per_chunk * (start_resumable_chunk - 1); range_num_samples = num_chunks * num_samples_per_chunk; } + + /* Round after doing the multiplications with num_chunks and num_samples_per_chunk + * to allow for many small chunks. */ + int rounded_range_start_sample = (int)floor(range_start_sample + 0.5f); + int rounded_range_num_samples = max((int)floor(range_num_samples + 0.5f), 1); + /* Make sure we don't overshoot. */ - if(range_start_sample + range_num_samples > num_samples) { - range_num_samples = num_samples - range_num_samples; + if(rounded_range_start_sample + rounded_range_num_samples > num_samples) { + rounded_range_num_samples = num_samples - rounded_range_num_samples; } VLOG(1) << "Samples range start is " << range_start_sample << ", " << "number of samples to render is " << range_num_samples; - scene->integrator->start_sample = range_start_sample; + scene->integrator->start_sample = rounded_range_start_sample; scene->integrator->tag_update(scene); - session->tile_manager.range_start_sample = range_start_sample; - session->tile_manager.range_num_samples = range_num_samples; + session->tile_manager.range_start_sample = rounded_range_start_sample; + session->tile_manager.range_num_samples = rounded_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 |