From c82166ffcd88dcb5fe5b694faa33043f1a4979b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Tue, 18 Aug 2020 10:46:12 +0200 Subject: Cycles: move some Scene related methods out of Session This moves `Session::get_requested_device_features`, `Session::load_kernels`, and `Session::update_scene` out of `Session` and into `Scene`, as mentioned in D8544. Reviewed By: brecht Differential Revision: https://developer.blender.org/D8590 --- intern/cycles/device/device.h | 4 +- intern/cycles/render/scene.cpp | 162 +++++++++++++++++++++++++++++++++++++++ intern/cycles/render/scene.h | 18 +++++ intern/cycles/render/session.cpp | 160 +------------------------------------- intern/cycles/render/session.h | 14 ---- 5 files changed, 183 insertions(+), 175 deletions(-) (limited to 'intern') diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 115b05e3911..58472f645e0 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -180,7 +180,6 @@ class DeviceRequestedFeatures { DeviceRequestedFeatures() { /* TODO(sergey): Find more meaningful defaults. */ - experimental = false; max_nodes_group = 0; nodes_features = 0; use_hair = false; @@ -203,8 +202,7 @@ class DeviceRequestedFeatures { bool modified(const DeviceRequestedFeatures &requested_features) { - return !(experimental == requested_features.experimental && - max_nodes_group == requested_features.max_nodes_group && + return !(max_nodes_group == requested_features.max_nodes_group && nodes_features == requested_features.nodes_features && use_hair == requested_features.use_hair && use_hair_thick == requested_features.use_hair_thick && diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 9016a8d325f..e68ab335da4 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -29,6 +29,7 @@ #include "render/osl.h" #include "render/particles.h" #include "render/scene.h" +#include "render/session.h" #include "render/shader.h" #include "render/svm.h" #include "render/tables.h" @@ -109,6 +110,10 @@ Scene::Scene(const SceneParams ¶ms_, Device *device) image_manager = new ImageManager(device->info); particle_system_manager = new ParticleSystemManager(); bake_manager = new BakeManager(); + kernels_loaded = false; + + /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */ + max_closure_global = 1; /* OSL only works on the CPU */ if (device->info.has_osl) @@ -396,4 +401,161 @@ void Scene::collect_statistics(RenderStats *stats) image_manager->collect_statistics(stats); } +DeviceRequestedFeatures Scene::get_requested_device_features() +{ + DeviceRequestedFeatures requested_features; + + shader_manager->get_requested_features(this, &requested_features); + + /* This features are not being tweaked as often as shaders, + * so could be done selective magic for the viewport as well. + */ + bool use_motion = need_motion() == Scene::MotionType::MOTION_BLUR; + requested_features.use_hair = false; + requested_features.use_hair_thick = (params.hair_shape == CURVE_THICK); + requested_features.use_object_motion = false; + requested_features.use_camera_motion = use_motion && camera->use_motion(); + foreach (Object *object, objects) { + Geometry *geom = object->geometry; + if (use_motion) { + requested_features.use_object_motion |= object->use_motion() | geom->use_motion_blur; + requested_features.use_camera_motion |= geom->use_motion_blur; + } + if (object->is_shadow_catcher) { + requested_features.use_shadow_tricks = true; + } + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast(geom); +#ifdef WITH_OPENSUBDIV + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { + requested_features.use_patch_evaluation = true; + } +#endif + requested_features.use_true_displacement |= mesh->has_true_displacement(); + } + else if (geom->type == Geometry::HAIR) { + requested_features.use_hair = true; + } + } + + requested_features.use_background_light = light_manager->has_background_light(this); + + requested_features.use_baking = bake_manager->get_baking(); + requested_features.use_integrator_branched = (integrator->method == Integrator::BRANCHED_PATH); + if (film->denoising_data_pass) { + requested_features.use_denoising = true; + requested_features.use_shadow_tricks = true; + } + + return requested_features; +} + +bool Scene::update(Progress &progress, bool &kernel_switch_needed) +{ + /* update scene */ + if (need_update()) { + /* Updated used shader tag so we know which features are need for the kernel. */ + shader_manager->update_shaders_used(this); + + /* Update max_closures. */ + KernelIntegrator *kintegrator = &dscene.data.integrator; + if (params.background) { + kintegrator->max_closures = get_max_closure_count(); + } + else { + /* Currently viewport render is faster with higher max_closures, needs investigating. */ + kintegrator->max_closures = MAX_CLOSURE; + } + + /* Load render kernels, before device update where we upload data to the GPU. */ + bool new_kernels_needed = load_kernels(progress, false); + + progress.set_status("Updating Scene"); + MEM_GUARDED_CALL(&progress, device_update, device, progress); + + DeviceKernelStatus kernel_switch_status = device->get_active_kernel_switch_state(); + kernel_switch_needed = kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE || + kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_INVALID; + if (kernel_switch_status == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) { + progress.set_kernel_status("Compiling render kernels"); + } + if (new_kernels_needed || kernel_switch_needed) { + progress.set_kernel_status("Compiling render kernels"); + device->wait_for_availability(loaded_kernel_features); + progress.set_kernel_status(""); + } + + return true; + } + return false; +} + +bool Scene::load_kernels(Progress &progress, bool lock_scene) +{ + thread_scoped_lock scene_lock; + if (lock_scene) { + scene_lock = thread_scoped_lock(mutex); + } + + DeviceRequestedFeatures requested_features = get_requested_device_features(); + + if (!kernels_loaded || loaded_kernel_features.modified(requested_features)) { + progress.set_status("Loading render kernels (may take a few minutes the first time)"); + + scoped_timer timer; + + VLOG(2) << "Requested features:\n" << requested_features; + if (!device->load_kernels(requested_features)) { + string message = device->error_message(); + if (message.empty()) + message = "Failed loading render kernel, see console for errors"; + + progress.set_error(message); + progress.set_status(message); + progress.set_update(); + return false; + } + + progress.add_skip_time(timer, false); + VLOG(1) << "Total time spent loading kernels: " << time_dt() - timer.get_start(); + + kernels_loaded = true; + loaded_kernel_features = requested_features; + return true; + } + return false; +} + +int Scene::get_max_closure_count() +{ + if (shader_manager->use_osl()) { + /* OSL always needs the maximum as we can't predict the + * number of closures a shader might generate. */ + return MAX_CLOSURE; + } + + int max_closures = 0; + for (int i = 0; i < shaders.size(); i++) { + Shader *shader = shaders[i]; + if (shader->used) { + int num_closures = shader->graph->get_num_closures(); + max_closures = max(max_closures, num_closures); + } + } + max_closure_global = max(max_closure_global, max_closures); + + if (max_closure_global > MAX_CLOSURE) { + /* This is usually harmless as more complex shader tend to get many + * closures discarded due to mixing or low weights. We need to limit + * to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it + * avoids excessive memory usage for split kernels. */ + VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > " + << MAX_CLOSURE; + + max_closure_global = MAX_CLOSURE; + } + + return max_closure_global; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 67616262c03..24f431b82fd 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -22,6 +22,7 @@ #include "render/image.h" #include "render/shader.h" +#include "device/device.h" #include "device/device_memory.h" #include "util/util_param.h" @@ -276,6 +277,8 @@ class Scene { void collect_statistics(RenderStats *stats); + bool update(Progress &progress, bool &kernel_switch_needed); + protected: /* Check if some heavy data worth logging was updated. * Mainly used to suppress extra annoying logging. @@ -283,6 +286,21 @@ class Scene { bool need_data_update(); void free_memory(bool final); + + bool kernels_loaded; + DeviceRequestedFeatures loaded_kernel_features; + + bool load_kernels(Progress &progress, bool lock_scene = true); + + /* ** Split kernel routines ** */ + + DeviceRequestedFeatures get_requested_device_features(); + + /* Maximumnumber of closure during session lifetime. */ + int max_closure_global; + + /* Get maximum number of closures to be used in kernel. */ + int get_max_closure_count(); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 70c4214c684..c22e29043d3 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -90,10 +90,6 @@ Session::Session(const SessionParams ¶ms_) gpu_draw_ready = false; gpu_need_display_buffer_update = false; pause = false; - kernels_loaded = false; - - /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */ - max_closure_global = 1; } Session::~Session() @@ -767,95 +763,6 @@ void Session::run_cpu() update_progressive_refine(true); } -DeviceRequestedFeatures Session::get_requested_device_features() -{ - /* TODO(sergey): Consider moving this to the Scene level. */ - DeviceRequestedFeatures requested_features; - requested_features.experimental = params.experimental; - - scene->shader_manager->get_requested_features(scene, &requested_features); - - /* This features are not being tweaked as often as shaders, - * so could be done selective magic for the viewport as well. - */ - bool use_motion = scene->need_motion() == Scene::MotionType::MOTION_BLUR; - requested_features.use_hair = false; - requested_features.use_hair_thick = (scene->params.hair_shape == CURVE_THICK); - requested_features.use_object_motion = false; - requested_features.use_camera_motion = use_motion && scene->camera->use_motion(); - foreach (Object *object, scene->objects) { - Geometry *geom = object->geometry; - if (use_motion) { - requested_features.use_object_motion |= object->use_motion() | geom->use_motion_blur; - requested_features.use_camera_motion |= geom->use_motion_blur; - } - if (object->is_shadow_catcher) { - requested_features.use_shadow_tricks = true; - } - if (geom->type == Geometry::MESH) { - Mesh *mesh = static_cast(geom); -#ifdef WITH_OPENSUBDIV - if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { - requested_features.use_patch_evaluation = true; - } -#endif - requested_features.use_true_displacement |= mesh->has_true_displacement(); - } - else if (geom->type == Geometry::HAIR) { - requested_features.use_hair = true; - } - } - - requested_features.use_background_light = scene->light_manager->has_background_light(scene); - - BakeManager *bake_manager = scene->bake_manager; - requested_features.use_baking = bake_manager->get_baking(); - requested_features.use_integrator_branched = (scene->integrator->method == - Integrator::BRANCHED_PATH); - if (params.denoising.use || params.denoising.store_passes) { - requested_features.use_denoising = true; - requested_features.use_shadow_tricks = true; - } - - return requested_features; -} - -bool Session::load_kernels(bool lock_scene) -{ - thread_scoped_lock scene_lock; - if (lock_scene) { - scene_lock = thread_scoped_lock(scene->mutex); - } - - DeviceRequestedFeatures requested_features = get_requested_device_features(); - - if (!kernels_loaded || loaded_kernel_features.modified(requested_features)) { - progress.set_status("Loading render kernels (may take a few minutes the first time)"); - - scoped_timer timer; - - VLOG(2) << "Requested features:\n" << requested_features; - if (!device->load_kernels(requested_features)) { - string message = device->error_message(); - if (message.empty()) - message = "Failed loading render kernel, see console for errors"; - - progress.set_error(message); - progress.set_status(message); - progress.set_update(); - return false; - } - - progress.add_skip_time(timer, false); - VLOG(1) << "Total time spent loading kernels: " << time_dt() - timer.get_start(); - - kernels_loaded = true; - loaded_kernel_features = requested_features; - return true; - } - return false; -} - void Session::run() { if (params.use_profiling && (params.device.type == DEVICE_CPU)) { @@ -1032,39 +939,8 @@ bool Session::update_scene() } } - /* update scene */ - if (scene->need_update()) { - /* Updated used shader tag so we know which features are need for the kernel. */ - scene->shader_manager->update_shaders_used(scene); - - /* Update max_closures. */ - KernelIntegrator *kintegrator = &scene->dscene.data.integrator; - if (params.background) { - kintegrator->max_closures = get_max_closure_count(); - } - else { - /* Currently viewport render is faster with higher max_closures, needs investigating. */ - kintegrator->max_closures = MAX_CLOSURE; - } - - /* Load render kernels, before device update where we upload data to the GPU. */ - bool new_kernels_needed = load_kernels(false); - - progress.set_status("Updating Scene"); - MEM_GUARDED_CALL(&progress, scene->device_update, device, progress); - - DeviceKernelStatus kernel_switch_status = device->get_active_kernel_switch_state(); - bool kernel_switch_needed = kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE || - kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_INVALID; - if (kernel_switch_status == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) { - progress.set_kernel_status("Compiling render kernels"); - } - if (new_kernels_needed || kernel_switch_needed) { - progress.set_kernel_status("Compiling render kernels"); - device->wait_for_availability(loaded_kernel_features); - progress.set_kernel_status(""); - } - + bool kernel_switch_needed = false; + if (scene->update(progress, kernel_switch_needed)) { if (kernel_switch_needed) { reset(tile_manager.params, params.samples); } @@ -1334,36 +1210,4 @@ void Session::collect_statistics(RenderStats *render_stats) } } -int Session::get_max_closure_count() -{ - if (scene->shader_manager->use_osl()) { - /* OSL always needs the maximum as we can't predict the - * number of closures a shader might generate. */ - return MAX_CLOSURE; - } - - int max_closures = 0; - for (int i = 0; i < scene->shaders.size(); i++) { - Shader *shader = scene->shaders[i]; - if (shader->used) { - int num_closures = shader->graph->get_num_closures(); - max_closures = max(max_closures, num_closures); - } - } - max_closure_global = max(max_closure_global, max_closures); - - if (max_closure_global > MAX_CLOSURE) { - /* This is usually harmless as more complex shader tend to get many - * closures discarded due to mixing or low weights. We need to limit - * to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it - * avoids excessive memory usage for split kernels. */ - VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > " - << MAX_CLOSURE; - - max_closure_global = MAX_CLOSURE; - } - - return max_closure_global; -} - CCL_NAMESPACE_END diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index e3ac054ead3..a22bf7731ae 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -157,7 +157,6 @@ class Session { void set_denoising_start_sample(int sample); bool update_scene(); - bool load_kernels(bool lock_scene = true); void device_free(); @@ -219,25 +218,12 @@ class Session { thread_mutex display_mutex; thread_condition_variable denoising_cond; - bool kernels_loaded; - DeviceRequestedFeatures loaded_kernel_features; - double reset_time; double last_update_time; double last_display_time; /* progressive refine */ bool update_progressive_refine(bool cancel); - - DeviceRequestedFeatures get_requested_device_features(); - - /* ** Split kernel routines ** */ - - /* Maximumnumber of closure during session lifetime. */ - int max_closure_global; - - /* Get maximum number of closures to be used in kernel. */ - int get_max_closure_count(); }; CCL_NAMESPACE_END -- cgit v1.2.3