Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/render/scene.cpp
| Show First 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | void Scene::free_memory(bool final) | ||||
| foreach (Object *o, objects) | foreach (Object *o, objects) | ||||
| delete o; | delete o; | ||||
| foreach (Geometry *g, geometry) | foreach (Geometry *g, geometry) | ||||
| delete g; | delete g; | ||||
| foreach (ParticleSystem *p, particle_systems) | foreach (ParticleSystem *p, particle_systems) | ||||
| delete p; | delete p; | ||||
| foreach (Light *l, lights) | foreach (Light *l, lights) | ||||
| delete l; | delete l; | ||||
| foreach (Pass *p, passes) | |||||
| delete p; | |||||
| geometry.clear(); | geometry.clear(); | ||||
| objects.clear(); | objects.clear(); | ||||
| lights.clear(); | lights.clear(); | ||||
| particle_systems.clear(); | particle_systems.clear(); | ||||
| procedurals.clear(); | procedurals.clear(); | ||||
| passes.clear(); | |||||
| if (device) { | if (device) { | ||||
| camera->device_free(device, &dscene, this); | camera->device_free(device, &dscene, this); | ||||
| film->device_free(device, &dscene, this); | film->device_free(device, &dscene, this); | ||||
| background->device_free(device, &dscene); | background->device_free(device, &dscene); | ||||
| integrator->device_free(device, &dscene, true); | integrator->device_free(device, &dscene, true); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | void Scene::device_update(Device *device_, Progress &progress) | ||||
| /* The order of updates is important, because there's dependencies between | /* The order of updates is important, because there's dependencies between | ||||
| * the different managers, using data computed by previous managers. | * the different managers, using data computed by previous managers. | ||||
| * | * | ||||
| * - Image manager uploads images used by shaders. | * - Image manager uploads images used by shaders. | ||||
| * - Camera may be used for adaptive subdivision. | * - Camera may be used for adaptive subdivision. | ||||
| * - Displacement shader must have all shader data available. | * - Displacement shader must have all shader data available. | ||||
| * - Light manager needs lookup tables and final mesh data to compute emission CDF. | * - Light manager needs lookup tables and final mesh data to compute emission CDF. | ||||
| * - Film needs light manager to run for use_light_visibility | |||||
| * - Lookup tables are done a second time to handle film tables | * - Lookup tables are done a second time to handle film tables | ||||
| */ | */ | ||||
| progress.set_status("Updating Shaders"); | progress.set_status("Updating Shaders"); | ||||
| shader_manager->device_update(device, &dscene, this, progress); | shader_manager->device_update(device, &dscene, this, progress); | ||||
| if (progress.get_cancel() || device->have_error()) | if (progress.get_cancel() || device->have_error()) | ||||
| return; | return; | ||||
| ▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | |||||
| void Scene::enable_update_stats() | void Scene::enable_update_stats() | ||||
| { | { | ||||
| if (!update_stats) { | if (!update_stats) { | ||||
| update_stats = new SceneUpdateStats(); | update_stats = new SceneUpdateStats(); | ||||
| } | } | ||||
| } | } | ||||
| DeviceRequestedFeatures Scene::get_requested_device_features() | void Scene::update_kernel_features() | ||||
| { | { | ||||
| DeviceRequestedFeatures requested_features; | if (!need_update()) { | ||||
| return; | |||||
| } | |||||
| shader_manager->get_requested_features(this, &requested_features); | /* These features are not being tweaked as often as shaders, | ||||
| * so could be done selective magic for the viewport as well. */ | |||||
| uint kernel_features = shader_manager->get_kernel_features(this); | |||||
| /* 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; | bool use_motion = need_motion() == Scene::MotionType::MOTION_BLUR; | ||||
| requested_features.use_hair = false; | kernel_features |= KERNEL_FEATURE_PATH_TRACING; | ||||
| requested_features.use_hair_thick = (params.hair_shape == CURVE_THICK); | if (params.hair_shape == CURVE_THICK) { | ||||
| requested_features.use_object_motion = false; | kernel_features |= KERNEL_FEATURE_HAIR_THICK; | ||||
| requested_features.use_camera_motion = use_motion && camera->use_motion(); | } | ||||
| if (use_motion && camera->use_motion()) { | |||||
| kernel_features |= KERNEL_FEATURE_CAMERA_MOTION; | |||||
| } | |||||
| foreach (Object *object, objects) { | foreach (Object *object, objects) { | ||||
| Geometry *geom = object->get_geometry(); | Geometry *geom = object->get_geometry(); | ||||
| if (use_motion) { | if (use_motion) { | ||||
| requested_features.use_object_motion |= object->use_motion() | geom->get_use_motion_blur(); | if (object->use_motion() || geom->get_use_motion_blur()) { | ||||
| requested_features.use_camera_motion |= geom->get_use_motion_blur(); | kernel_features |= KERNEL_FEATURE_OBJECT_MOTION; | ||||
| } | |||||
| if (geom->get_use_motion_blur()) { | |||||
| kernel_features |= KERNEL_FEATURE_CAMERA_MOTION; | |||||
| } | |||||
| } | } | ||||
| if (object->get_is_shadow_catcher()) { | if (object->get_is_shadow_catcher()) { | ||||
| requested_features.use_shadow_tricks = true; | kernel_features |= KERNEL_FEATURE_SHADOW_CATCHER; | ||||
| } | } | ||||
| if (geom->is_mesh()) { | if (geom->is_mesh()) { | ||||
| Mesh *mesh = static_cast<Mesh *>(geom); | Mesh *mesh = static_cast<Mesh *>(geom); | ||||
| #ifdef WITH_OPENSUBDIV | #ifdef WITH_OPENSUBDIV | ||||
| if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) { | if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) { | ||||
| requested_features.use_patch_evaluation = true; | kernel_features |= KERNEL_FEATURE_PATCH_EVALUATION; | ||||
| } | } | ||||
| #endif | #endif | ||||
| requested_features.use_true_displacement |= mesh->has_true_displacement(); | |||||
| } | } | ||||
| else if (geom->is_hair()) { | else if (geom->is_hair()) { | ||||
| requested_features.use_hair = true; | kernel_features |= KERNEL_FEATURE_HAIR; | ||||
| } | } | ||||
| } | } | ||||
| requested_features.use_background_light = light_manager->has_background_light(this); | if (bake_manager->get_baking()) { | ||||
| kernel_features |= KERNEL_FEATURE_BAKING; | |||||
| requested_features.use_baking = bake_manager->get_baking(); | |||||
| requested_features.use_integrator_branched = (integrator->get_method() == | |||||
| Integrator::BRANCHED_PATH); | |||||
| if (film->get_denoising_data_pass()) { | |||||
| requested_features.use_denoising = true; | |||||
| requested_features.use_shadow_tricks = true; | |||||
| } | } | ||||
| return requested_features; | kernel_features |= film->get_kernel_features(this); | ||||
| dscene.data.kernel_features = kernel_features; | |||||
| /* Currently viewport render is faster with higher max_closures, needs investigating. */ | |||||
| const uint max_closures = (params.background) ? get_max_closure_count() : MAX_CLOSURE; | |||||
| dscene.data.max_closures = max_closures; | |||||
| dscene.data.max_shaders = shaders.size(); | |||||
| } | } | ||||
| bool Scene::update(Progress &progress, bool &kernel_switch_needed) | bool Scene::update(Progress &progress) | ||||
| { | { | ||||
| /* update scene */ | if (!need_update()) { | ||||
| if (need_update()) { | return false; | ||||
| /* 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. */ | /* Load render kernels, before device update where we upload data to the GPU. */ | ||||
| bool new_kernels_needed = load_kernels(progress, false); | load_kernels(progress, false); | ||||
| /* Upload scene data to the GPU. */ | |||||
| progress.set_status("Updating Scene"); | progress.set_status("Updating Scene"); | ||||
| MEM_GUARDED_CALL(&progress, device_update, device, progress); | 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 (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 true; | ||||
| } | } | ||||
| return false; | |||||
| static void log_kernel_features(const uint features) | |||||
| { | |||||
| VLOG(2) << "Requested features:\n"; | |||||
| VLOG(2) << "Use BSDF " << string_from_bool(features & KERNEL_FEATURE_NODE_BSDF) << "\n"; | |||||
| VLOG(2) << "Use Principled BSDF " << string_from_bool(features & KERNEL_FEATURE_PRINCIPLED) | |||||
| << "\n"; | |||||
| VLOG(2) << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION) << "\n"; | |||||
| VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n"; | |||||
| VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_NODE_HAIR) << "\n"; | |||||
| VLOG(2) << "Use Bump " << string_from_bool(features & KERNEL_FEATURE_NODE_BUMP) << "\n"; | |||||
| VLOG(2) << "Use Voronoi " << string_from_bool(features & KERNEL_FEATURE_NODE_VORONOI_EXTRA) | |||||
| << "\n"; | |||||
| VLOG(2) << "Use Shader Raytrace " << string_from_bool(features & KERNEL_FEATURE_NODE_RAYTRACE) | |||||
| << "\n"; | |||||
| VLOG(2) << "Use Transparent " << string_from_bool(features & KERNEL_FEATURE_TRANSPARENT) << "\n"; | |||||
| VLOG(2) << "Use Denoising " << string_from_bool(features & KERNEL_FEATURE_DENOISING) << "\n"; | |||||
| VLOG(2) << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING) | |||||
| << "\n"; | |||||
| VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n"; | |||||
| VLOG(2) << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION) | |||||
| << "\n"; | |||||
| VLOG(2) << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION) | |||||
| << "\n"; | |||||
| VLOG(2) << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n"; | |||||
| VLOG(2) << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n"; | |||||
| VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n"; | |||||
| VLOG(2) << "Use Patch Evaluation " | |||||
| << string_from_bool(features & KERNEL_FEATURE_PATCH_EVALUATION) << "\n"; | |||||
| VLOG(2) << "Use Shadow Catcher " << string_from_bool(features & KERNEL_FEATURE_SHADOW_CATCHER) | |||||
| << "\n"; | |||||
| } | } | ||||
| bool Scene::load_kernels(Progress &progress, bool lock_scene) | bool Scene::load_kernels(Progress &progress, bool lock_scene) | ||||
| { | { | ||||
| thread_scoped_lock scene_lock; | thread_scoped_lock scene_lock; | ||||
| if (lock_scene) { | if (lock_scene) { | ||||
| scene_lock = thread_scoped_lock(mutex); | scene_lock = thread_scoped_lock(mutex); | ||||
| } | } | ||||
| DeviceRequestedFeatures requested_features = get_requested_device_features(); | const uint kernel_features = dscene.data.kernel_features; | ||||
| if (!kernels_loaded || loaded_kernel_features.modified(requested_features)) { | if (!kernels_loaded || loaded_kernel_features != kernel_features) { | ||||
| progress.set_status("Loading render kernels (may take a few minutes the first time)"); | progress.set_status("Loading render kernels (may take a few minutes the first time)"); | ||||
| scoped_timer timer; | scoped_timer timer; | ||||
| VLOG(2) << "Requested features:\n" << requested_features; | log_kernel_features(kernel_features); | ||||
| if (!device->load_kernels(requested_features)) { | if (!device->load_kernels(kernel_features)) { | ||||
| string message = device->error_message(); | string message = device->error_message(); | ||||
| if (message.empty()) | if (message.empty()) | ||||
| message = "Failed loading render kernel, see console for errors"; | message = "Failed loading render kernel, see console for errors"; | ||||
| progress.set_error(message); | progress.set_error(message); | ||||
| progress.set_status(message); | progress.set_status(message); | ||||
| progress.set_update(); | progress.set_update(); | ||||
| return false; | return false; | ||||
| } | } | ||||
| kernels_loaded = true; | kernels_loaded = true; | ||||
| loaded_kernel_features = requested_features; | loaded_kernel_features = kernel_features; | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| int Scene::get_max_closure_count() | int Scene::get_max_closure_count() | ||||
| { | { | ||||
| if (shader_manager->use_osl()) { | if (shader_manager->use_osl()) { | ||||
| Show All 21 Lines | VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > " | ||||
| << MAX_CLOSURE; | << MAX_CLOSURE; | ||||
| max_closure_global = MAX_CLOSURE; | max_closure_global = MAX_CLOSURE; | ||||
| } | } | ||||
| return max_closure_global; | return max_closure_global; | ||||
| } | } | ||||
| bool Scene::has_shadow_catcher() | |||||
| { | |||||
| if (shadow_catcher_modified_) { | |||||
| has_shadow_catcher_ = false; | |||||
| for (Object *object : objects) { | |||||
| if (object->get_is_shadow_catcher()) { | |||||
| has_shadow_catcher_ = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| shadow_catcher_modified_ = false; | |||||
| } | |||||
| return has_shadow_catcher_; | |||||
| } | |||||
| void Scene::tag_shadow_catcher_modified() | |||||
| { | |||||
| shadow_catcher_modified_ = true; | |||||
| } | |||||
| template<> Light *Scene::create_node<Light>() | template<> Light *Scene::create_node<Light>() | ||||
| { | { | ||||
| Light *node = new Light(); | Light *node = new Light(); | ||||
| node->set_owner(this); | node->set_owner(this); | ||||
| lights.push_back(node); | lights.push_back(node); | ||||
| light_manager->tag_update(this, LightManager::LIGHT_ADDED); | light_manager->tag_update(this, LightManager::LIGHT_ADDED); | ||||
| return node; | return node; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | #ifdef WITH_ALEMBIC | ||||
| procedurals.push_back(node); | procedurals.push_back(node); | ||||
| procedural_manager->tag_update(); | procedural_manager->tag_update(); | ||||
| return node; | return node; | ||||
| #else | #else | ||||
| return nullptr; | return nullptr; | ||||
| #endif | #endif | ||||
| } | } | ||||
| template<> Pass *Scene::create_node<Pass>() | |||||
| { | |||||
| Pass *node = new Pass(); | |||||
| node->set_owner(this); | |||||
| passes.push_back(node); | |||||
| film->tag_modified(); | |||||
| return node; | |||||
| } | |||||
| template<typename T> void delete_node_from_array(vector<T> &nodes, T node) | template<typename T> void delete_node_from_array(vector<T> &nodes, T node) | ||||
| { | { | ||||
| for (size_t i = 0; i < nodes.size(); ++i) { | for (size_t i = 0; i < nodes.size(); ++i) { | ||||
| if (nodes[i] == node) { | if (nodes[i] == node) { | ||||
| std::swap(nodes[i], nodes[nodes.size() - 1]); | std::swap(nodes[i], nodes[nodes.size() - 1]); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| #ifdef WITH_ALEMBIC | #ifdef WITH_ALEMBIC | ||||
| delete_node_impl(static_cast<Procedural *>(node)); | delete_node_impl(static_cast<Procedural *>(node)); | ||||
| #else | #else | ||||
| (void)node; | (void)node; | ||||
| #endif | #endif | ||||
| } | } | ||||
| template<> void Scene::delete_node_impl(Pass *node) | |||||
| { | |||||
| delete_node_from_array(passes, node); | |||||
| film->tag_modified(); | |||||
| } | |||||
| template<typename T> | template<typename T> | ||||
| static void remove_nodes_in_set(const set<T *> &nodes_set, | static void remove_nodes_in_set(const set<T *> &nodes_set, | ||||
| vector<T *> &nodes_array, | vector<T *> &nodes_array, | ||||
| const NodeOwner *owner) | const NodeOwner *owner) | ||||
| { | { | ||||
| size_t new_size = nodes_array.size(); | size_t new_size = nodes_array.size(); | ||||
| for (size_t i = 0; i < new_size; ++i) { | for (size_t i = 0; i < new_size; ++i) { | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner) | template<> void Scene::delete_nodes(const set<Procedural *> &nodes, const NodeOwner *owner) | ||||
| { | { | ||||
| remove_nodes_in_set(nodes, procedurals, owner); | remove_nodes_in_set(nodes, procedurals, owner); | ||||
| procedural_manager->tag_update(); | procedural_manager->tag_update(); | ||||
| } | } | ||||
| template<> void Scene::delete_nodes(const set<Pass *> &nodes, const NodeOwner *owner) | |||||
| { | |||||
| remove_nodes_in_set(nodes, passes, owner); | |||||
| film->tag_modified(); | |||||
| } | |||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||