diff options
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/alembic.cpp | 154 | ||||
-rw-r--r-- | intern/cycles/render/alembic.h | 39 | ||||
-rw-r--r-- | intern/cycles/render/alembic_read.cpp | 16 | ||||
-rw-r--r-- | intern/cycles/render/geometry.cpp | 20 | ||||
-rw-r--r-- | intern/cycles/render/graph.cpp | 4 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 20 | ||||
-rw-r--r-- | intern/cycles/render/object.cpp | 3 | ||||
-rw-r--r-- | intern/cycles/render/object.h | 2 | ||||
-rw-r--r-- | intern/cycles/render/session.cpp | 287 | ||||
-rw-r--r-- | intern/cycles/render/session.h | 45 | ||||
-rw-r--r-- | intern/cycles/render/shader.h | 8 |
11 files changed, 397 insertions, 201 deletions
diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 6713531c9b0..69bc0712674 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -25,6 +25,7 @@ #include "render/shader.h" #include "util/util_foreach.h" +#include "util/util_logging.h" #include "util/util_progress.h" #include "util/util_transform.h" #include "util/util_vector.h" @@ -211,6 +212,35 @@ void CachedData::set_time_sampling(TimeSampling time_sampling) } } +size_t CachedData::memory_used() const +{ + size_t mem_used = 0; + + mem_used += curve_first_key.memory_used(); + mem_used += curve_keys.memory_used(); + mem_used += curve_radius.memory_used(); + mem_used += curve_shader.memory_used(); + mem_used += num_ngons.memory_used(); + mem_used += shader.memory_used(); + mem_used += subd_creases_edge.memory_used(); + mem_used += subd_creases_weight.memory_used(); + mem_used += subd_face_corners.memory_used(); + mem_used += subd_num_corners.memory_used(); + mem_used += subd_ptex_offset.memory_used(); + mem_used += subd_smooth.memory_used(); + mem_used += subd_start_corner.memory_used(); + mem_used += transforms.memory_used(); + mem_used += triangles.memory_used(); + mem_used += uv_loops.memory_used(); + mem_used += vertices.memory_used(); + + for (const CachedAttribute &attr : attributes) { + mem_used += attr.data.memory_used(); + } + + return mem_used; +} + static M44d convert_yup_zup(const M44d &mtx, float scale_mult) { V3d scale, shear, rotation, translation; @@ -385,6 +415,8 @@ NODE_DEFINE(AlembicObject) SOCKET_STRING(path, "Alembic Path", ustring()); SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", Shader::get_node_type()); + SOCKET_BOOLEAN(ignore_subdivision, "Ignore Subdivision", true); + SOCKET_INT(subd_max_level, "Max Subdivision Level", 1); SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f); @@ -470,6 +502,33 @@ void AlembicObject::load_data_in_cache(CachedData &cached_data, cached_data.clear(); + if (this->get_ignore_subdivision()) { + PolyMeshSchemaData data; + data.topology_variance = schema.getTopologyVariance(); + data.time_sampling = schema.getTimeSampling(); + data.positions = schema.getPositionsProperty(); + data.face_counts = schema.getFaceCountsProperty(); + data.face_indices = schema.getFaceIndicesProperty(); + data.num_samples = schema.getNumSamples(); + data.velocities = schema.getVelocitiesProperty(); + data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders()); + + read_geometry_data(proc, cached_data, data, progress); + + if (progress.get_cancel()) { + return; + } + + /* Use the schema as the base compound property to also be able to look for top level + * properties. */ + read_attributes( + proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress); + + cached_data.invalidate_last_loaded_time(true); + data_loaded = true; + return; + } + SubDSchemaData data; data.time_sampling = schema.getTimeSampling(); data.num_samples = schema.getNumSamples(); @@ -677,6 +736,9 @@ NODE_DEFINE(AlembicProcedural) SOCKET_NODE_ARRAY(objects, "Objects", AlembicObject::get_node_type()); + SOCKET_BOOLEAN(use_prefetch, "Use Prefetch", true); + SOCKET_INT(prefetch_cache_size, "Prefetch Cache Size", 4096); + return type; } @@ -781,6 +843,43 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate); + /* Clear the subdivision caches as the data is stored differently. */ + for (Node *node : objects) { + AlembicObject *object = static_cast<AlembicObject *>(node); + + if (object->schema_type != AlembicObject::SUBD) { + continue; + } + + if (object->ignore_subdivision_is_modified()) { + object->clear_cache(); + } + } + + if (use_prefetch_is_modified()) { + if (!use_prefetch) { + for (Node *node : objects) { + AlembicObject *object = static_cast<AlembicObject *>(node); + object->clear_cache(); + } + } + } + + if (prefetch_cache_size_is_modified()) { + /* Check whether the current memory usage fits in the new requested size, + * abort the render if it is any higher. */ + size_t memory_used = 0ul; + for (Node *node : objects) { + AlembicObject *object = static_cast<AlembicObject *>(node); + memory_used += object->get_cached_data().memory_used(); + } + + if (memory_used > get_prefetch_cache_size_in_bytes()) { + progress.set_error("Error: Alembic Procedural memory limit reached"); + return; + } + } + build_caches(progress); foreach (Node *node, objects) { @@ -959,14 +1058,6 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame update_attributes(mesh->attributes, cached_data, frame_time); - /* we don't yet support arbitrary attributes, for now add vertex - * coordinates as generated coordinates if requested */ - if (mesh->need_attribute(scene_, ATTR_STD_GENERATED)) { - Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); - memcpy( - attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size()); - } - if (mesh->is_modified()) { bool need_rebuild = mesh->triangles_is_modified(); mesh->tag_update(scene_, need_rebuild); @@ -975,13 +1066,13 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time) { - CachedData &cached_data = abc_object->get_cached_data(); - - if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) { - /* need to reset the current data is something changed */ - cached_data.invalidate_last_loaded_time(); + if (abc_object->get_ignore_subdivision()) { + read_mesh(abc_object, frame_time); + return; } + CachedData &cached_data = abc_object->get_cached_data(); + /* Update sockets. */ Object *object = abc_object->get_object(); @@ -996,6 +1087,11 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame return; } + if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) { + /* need to reset the current data is something changed */ + cached_data.invalidate_last_loaded_time(); + } + Mesh *mesh = static_cast<Mesh *>(object->get_geometry()); /* Make sure shader ids are also updated. */ @@ -1053,14 +1149,6 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame update_attributes(mesh->subd_attributes, cached_data, frame_time); - /* we don't yet support arbitrary attributes, for now add vertex - * coordinates as generated coordinates if requested */ - if (mesh->need_attribute(scene_, ATTR_STD_GENERATED)) { - Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); - memcpy( - attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size()); - } - if (mesh->is_modified()) { bool need_rebuild = (mesh->triangles_is_modified()) || (mesh->subd_num_corners_is_modified()) || @@ -1110,17 +1198,6 @@ void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t fra update_attributes(hair->attributes, cached_data, frame_time); - /* we don't yet support arbitrary attributes, for now add first keys as generated coordinates if - * requested */ - if (hair->need_attribute(scene_, ATTR_STD_GENERATED)) { - Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED); - float3 *generated = attr_generated->data_float3(); - - for (size_t i = 0; i < hair->num_curves(); i++) { - generated[i] = hair->get_curve_keys()[hair->get_curve(i).first_key]; - } - } - const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified()); hair->tag_update(scene_, rebuild); } @@ -1280,6 +1357,8 @@ void AlembicProcedural::walk_hierarchy( void AlembicProcedural::build_caches(Progress &progress) { + size_t memory_used = 0; + for (Node *node : objects) { AlembicObject *object = static_cast<AlembicObject *>(node); @@ -1333,7 +1412,18 @@ void AlembicProcedural::build_caches(Progress &progress) if (scale_is_modified() || object->get_cached_data().transforms.size() == 0) { object->setup_transform_cache(object->get_cached_data(), scale); } + + memory_used += object->get_cached_data().memory_used(); + + if (use_prefetch) { + if (memory_used > get_prefetch_cache_size_in_bytes()) { + progress.set_error("Error: Alembic Procedural memory limit reached"); + return; + } + } } + + VLOG(1) << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index 61c0e40fe4a..8e166a5ab04 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -272,6 +272,21 @@ template<typename T> class DataStore { node->set(*socket, value); } + size_t memory_used() const + { + if constexpr (is_array<T>::value) { + size_t mem_used = 0; + + for (const T &array : data) { + mem_used += array.size() * sizeof(array[0]); + } + + return mem_used; + } + + return data.size() * sizeof(T); + } + private: const TimeIndexPair &get_index_for_time(double time) const { @@ -332,6 +347,8 @@ struct CachedData { void invalidate_last_loaded_time(bool attributes_only = false); void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling); + + size_t memory_used() const; }; /* Representation of an Alembic object for the AlembicProcedural. @@ -353,6 +370,10 @@ class AlembicObject : public Node { /* Shaders used for rendering. */ NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders) + /* Treat this subdivision object as a regular polygon mesh, so no subdivision will be performed. + */ + NODE_SOCKET_API(bool, ignore_subdivision) + /* Maximum number of subdivisions for ISubD objects. */ NODE_SOCKET_API(int, subd_max_level) @@ -416,6 +437,11 @@ class AlembicObject : public Node { return cached_data_.is_constant(); } + void clear_cache() + { + cached_data_.clear(); + } + Object *object = nullptr; bool data_loaded = false; @@ -473,6 +499,13 @@ class AlembicProcedural : public Procedural { * software. */ NODE_SOCKET_API(float, scale) + /* Cache controls */ + NODE_SOCKET_API(bool, use_prefetch) + + /* Memory limit for the cache, if the data does not fit within this limit, rendering is aborted. + */ + NODE_SOCKET_API(int, prefetch_cache_size) + AlembicProcedural(); ~AlembicProcedural(); @@ -522,6 +555,12 @@ class AlembicProcedural : public Procedural { void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time); void build_caches(Progress &progress); + + size_t get_prefetch_cache_size_in_bytes() const + { + /* prefetch_cache_size is in megabytes, so convert to bytes. */ + return static_cast<size_t>(prefetch_cache_size) * 1024 * 1024; + } }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/alembic_read.cpp b/intern/cycles/render/alembic_read.cpp index c53ec668938..b105af63b44 100644 --- a/intern/cycles/render/alembic_read.cpp +++ b/intern/cycles/render/alembic_read.cpp @@ -44,9 +44,19 @@ static set<chrono_t> get_relevant_sample_times(AlembicProcedural *proc, return result; } - // load the data for the entire animation - const double start_frame = static_cast<double>(proc->get_start_frame()); - const double end_frame = static_cast<double>(proc->get_end_frame()); + double start_frame; + double end_frame; + + if (proc->get_use_prefetch()) { + // load the data for the entire animation + start_frame = static_cast<double>(proc->get_start_frame()); + end_frame = static_cast<double>(proc->get_end_frame()); + } + else { + // load the data for the current frame + start_frame = static_cast<double>(proc->get_frame()); + end_frame = start_frame; + } const double frame_rate = static_cast<double>(proc->get_frame_rate()); const double start_time = start_frame / frame_rate; diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 30b19104ccf..b01b1fe5a77 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -788,6 +788,11 @@ void GeometryManager::device_update_attributes(Device *device, foreach (AttributeRequest &req, attributes.requests) { Attribute *attr = geom->attributes.find(req); + /* Vertex normals are stored in DeviceScene.tri_vnormal. */ + if (attr && attr->std == ATTR_STD_VERTEX_NORMAL) { + continue; + } + update_attribute_element_size(geom, attr, ATTR_PRIM_GEOMETRY, @@ -800,6 +805,11 @@ void GeometryManager::device_update_attributes(Device *device, Mesh *mesh = static_cast<Mesh *>(geom); Attribute *subd_attr = mesh->subd_attributes.find(req); + /* Vertex normals are stored in DeviceScene.tri_vnormal. */ + if (subd_attr && subd_attr->std == ATTR_STD_VERTEX_NORMAL) { + continue; + } + update_attribute_element_size(mesh, subd_attr, ATTR_PRIM_SUBD, @@ -854,6 +864,11 @@ void GeometryManager::device_update_attributes(Device *device, Attribute *attr = geom->attributes.find(req); if (attr) { + /* Vertex normals are stored in DeviceScene.tri_vnormal. */ + if (attr->std == ATTR_STD_VERTEX_NORMAL) { + continue; + } + /* force a copy if we need to reallocate all the data */ attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; } @@ -877,6 +892,11 @@ void GeometryManager::device_update_attributes(Device *device, Attribute *subd_attr = mesh->subd_attributes.find(req); if (subd_attr) { + /* Vertex normals are stored in DeviceScene.tri_vnormal. */ + if (subd_attr->std == ATTR_STD_VERTEX_NORMAL) { + continue; + } + /* force a copy if we need to reallocate all the data */ subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)]; } diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index a290eb4de2b..9c356656f81 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -158,13 +158,13 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) foreach (ShaderInput *input, inputs) { if (!input->link) { if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) { - if (shader->has_surface) + if (shader->has_surface_link()) attributes->add(ATTR_STD_GENERATED); if (shader->has_volume) attributes->add(ATTR_STD_GENERATED_TRANSFORM); } else if (input->flags() & SocketType::LINK_TEXTURE_UV) { - if (shader->has_surface) + if (shader->has_surface_link()) attributes->add(ATTR_STD_UV); } } diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 2477a96bc44..7337e19a929 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -353,7 +353,7 @@ void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attribute #ifdef WITH_PTEX /* todo: avoid loading other texture coordinates when using ptex, * and hide texture coordinate socket in the UI */ - if (shader->has_surface && string_endswith(filename, ".ptx")) { + if (shader->has_surface_link() && string_endswith(filename, ".ptx")) { /* ptex */ attributes->add(ATTR_STD_PTEX_FACE_ID); attributes->add(ATTR_STD_PTEX_UV); @@ -567,7 +567,7 @@ ImageParams EnvironmentTextureNode::image_params() const void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes) { #ifdef WITH_PTEX - if (shader->has_surface && string_endswith(filename, ".ptx")) { + if (shader->has_surface_link() && string_endswith(filename, ".ptx")) { /* ptex */ attributes->add(ATTR_STD_PTEX_FACE_ID); attributes->add(ATTR_STD_PTEX_UV); @@ -2335,7 +2335,7 @@ AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(get_node_type()) void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if (shader->has_surface) { + if (shader->has_surface_link()) { ShaderInput *tangent_in = input("Tangent"); if (!tangent_in->link) @@ -2859,7 +2859,7 @@ bool PrincipledBsdfNode::has_surface_bssrdf() void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if (shader->has_surface) { + if (shader->has_surface_link()) { ShaderInput *tangent_in = input("Tangent"); if (!tangent_in->link) @@ -3700,7 +3700,7 @@ GeometryNode::GeometryNode() : ShaderNode(get_node_type()) void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if (shader->has_surface) { + if (shader->has_surface_link()) { if (!output("Tangent")->links.empty()) { attributes->add(ATTR_STD_GENERATED); } @@ -3846,7 +3846,7 @@ TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(get_node_type()) void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if (shader->has_surface) { + if (shader->has_surface_link()) { if (!from_dupli) { if (!output("Generated")->links.empty()) attributes->add(ATTR_STD_GENERATED); @@ -4404,7 +4404,7 @@ HairInfoNode::HairInfoNode() : ShaderNode(get_node_type()) void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if (shader->has_surface) { + if (shader->has_surface_link()) { ShaderOutput *intercept_out = output("Intercept"); if (!intercept_out->links.empty()) @@ -6760,7 +6760,7 @@ NormalMapNode::NormalMapNode() : ShaderNode(get_node_type()) void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if (shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) { + if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) { if (attribute.empty()) { attributes->add(ATTR_STD_UV_TANGENT); attributes->add(ATTR_STD_UV_TANGENT_SIGN); @@ -6854,7 +6854,7 @@ TangentNode::TangentNode() : ShaderNode(get_node_type()) void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if (shader->has_surface) { + if (shader->has_surface_link()) { if (direction_type == NODE_TANGENT_UVMAP) { if (attribute.empty()) attributes->add(ATTR_STD_UV_TANGENT); @@ -7037,7 +7037,7 @@ void VectorDisplacementNode::constant_fold(const ConstantFolder &folder) void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if (shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) { + if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) { if (attribute.empty()) { attributes->add(ATTR_STD_UV_TANGENT); attributes->add(ATTR_STD_UV_TANGENT_SIGN); diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 5fe4e9ed57f..c88d94fe4c2 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -102,6 +102,8 @@ NODE_DEFINE(Object) SOCKET_NODE(particle_system, "Particle System", ParticleSystem::get_node_type()); SOCKET_INT(particle_index, "Particle Index", 0); + SOCKET_FLOAT(ao_distance, "AO Distance", 0.0f); + return type; } @@ -428,6 +430,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s kobject.random_number = random_number; kobject.particle_index = particle_index; kobject.motion_offset = 0; + kobject.ao_distance = ob->ao_distance; if (geom->get_use_motion_blur()) { state->have_motion = true; diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index ebb7733c2aa..c52ddce48da 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -73,6 +73,8 @@ class Object : public Node { NODE_SOCKET_API(ParticleSystem *, particle_system); NODE_SOCKET_API(int, particle_index); + NODE_SOCKET_API(float, ao_distance) + Object(); ~Object(); diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 19d4a66353d..1b91c49f0ea 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -57,23 +57,26 @@ Session::Session(const SessionParams ¶ms_) stats(), profiler() { - device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background); + device_use_gl_ = ((params.device.type != DEVICE_CPU) && !params.background); TaskScheduler::init(params.threads); - session_thread = NULL; + session_thread_ = NULL; scene = NULL; - reset_time = 0.0; - last_update_time = 0.0; + reset_time_ = 0.0; + last_update_time_ = 0.0; - delayed_reset.do_reset = false; - delayed_reset.samples = 0; + delayed_reset_.do_reset = false; + delayed_reset_.samples = 0; - display_outdated = false; - gpu_draw_ready = false; - gpu_need_display_buffer_update = false; - pause = false; + display_outdated_ = false; + gpu_draw_ready_ = false; + gpu_need_display_buffer_update_ = false; + + pause_ = false; + cancel_ = false; + new_work_added_ = false; buffers = NULL; display = NULL; @@ -127,25 +130,26 @@ Session::~Session() void Session::start() { - if (!session_thread) { - session_thread = new thread(function_bind(&Session::run, this)); + if (!session_thread_) { + session_thread_ = new thread(function_bind(&Session::run, this)); } } void Session::cancel() { - if (session_thread) { + if (session_thread_) { /* wait for session thread to end */ progress.set_cancel("Exiting"); - gpu_need_display_buffer_update = false; - gpu_need_display_buffer_update_cond.notify_all(); + gpu_need_display_buffer_update_ = false; + gpu_need_display_buffer_update_cond_.notify_all(); { - thread_scoped_lock pause_lock(pause_mutex); - pause = false; + thread_scoped_lock pause_lock(pause_mutex_); + pause_ = false; + cancel_ = true; } - pause_cond.notify_all(); + pause_cond_.notify_all(); wait(); } @@ -153,9 +157,9 @@ void Session::cancel() bool Session::ready_to_reset() { - double dt = time_dt() - reset_time; + double dt = time_dt() - reset_time_; - if (!display_outdated) + if (!display_outdated_) return (dt > params.reset_timeout); else return (dt > params.cancel_timeout); @@ -165,48 +169,50 @@ bool Session::ready_to_reset() void Session::reset_gpu(BufferParams &buffer_params, int samples) { - thread_scoped_lock pause_lock(pause_mutex); + thread_scoped_lock pause_lock(pause_mutex_); /* block for buffer access and reset immediately. we can't do this * in the thread, because we need to allocate an OpenGL buffer, and * that only works in the main thread */ - thread_scoped_lock display_lock(display_mutex); - thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock display_lock(display_mutex_); + thread_scoped_lock buffers_lock(buffers_mutex_); - display_outdated = true; - reset_time = time_dt(); + display_outdated_ = true; + reset_time_ = time_dt(); reset_(buffer_params, samples); - gpu_need_display_buffer_update = false; - gpu_need_display_buffer_update_cond.notify_all(); + gpu_need_display_buffer_update_ = false; + gpu_need_display_buffer_update_cond_.notify_all(); + + new_work_added_ = true; - pause_cond.notify_all(); + pause_cond_.notify_all(); } bool Session::draw_gpu(BufferParams &buffer_params, DeviceDrawParams &draw_params) { /* block for buffer access */ - thread_scoped_lock display_lock(display_mutex); + thread_scoped_lock display_lock(display_mutex_); /* first check we already rendered something */ - if (gpu_draw_ready) { + if (gpu_draw_ready_) { /* then verify the buffers have the expected size, so we don't * draw previous results in a resized window */ if (buffer_params.width == display->params.width && buffer_params.height == display->params.height) { /* for CUDA we need to do tone-mapping still, since we can * only access GL buffers from the main thread. */ - if (gpu_need_display_buffer_update) { - thread_scoped_lock buffers_lock(buffers_mutex); + if (gpu_need_display_buffer_update_) { + thread_scoped_lock buffers_lock(buffers_mutex_); copy_to_display_buffer(tile_manager.state.sample); - gpu_need_display_buffer_update = false; - gpu_need_display_buffer_update_cond.notify_all(); + gpu_need_display_buffer_update_ = false; + gpu_need_display_buffer_update_cond_.notify_all(); } display->draw(device, draw_params); - if (display_outdated && (time_dt() - reset_time) > params.text_timeout) + if (display_outdated_ && (time_dt() - reset_time_) > params.text_timeout) return false; return true; @@ -220,9 +226,9 @@ void Session::run_gpu() { bool tiles_written = false; - reset_time = time_dt(); - last_update_time = time_dt(); - last_display_time = last_update_time; + reset_time_ = time_dt(); + last_update_time_ = time_dt(); + last_display_time_ = last_update_time_; progress.set_render_start_time(); @@ -255,7 +261,7 @@ void Session::run_gpu() /* buffers mutex is locked entirely while rendering each * sample, and released/reacquired on each iteration to allow * reset and draw in between */ - thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock buffers_lock(buffers_mutex_); /* update status and timing */ update_status_time(); @@ -273,17 +279,17 @@ void Session::run_gpu() /* update status and timing */ update_status_time(); - gpu_need_display_buffer_update = !delayed_denoise; - gpu_draw_ready = true; + gpu_need_display_buffer_update_ = !delayed_denoise; + gpu_draw_ready_ = true; progress.set_update(); /* wait for until display buffer is updated */ if (!params.background) { - while (gpu_need_display_buffer_update) { + while (gpu_need_display_buffer_update_) { if (progress.get_cancel()) break; - gpu_need_display_buffer_update_cond.wait(buffers_lock); + gpu_need_display_buffer_update_cond_.wait(buffers_lock); } } @@ -305,23 +311,23 @@ void Session::run_gpu() void Session::reset_cpu(BufferParams &buffer_params, int samples) { - thread_scoped_lock reset_lock(delayed_reset.mutex); - thread_scoped_lock pause_lock(pause_mutex); + thread_scoped_lock reset_lock(delayed_reset_.mutex); + thread_scoped_lock pause_lock(pause_mutex_); - display_outdated = true; - reset_time = time_dt(); + display_outdated_ = true; + reset_time_ = time_dt(); - delayed_reset.params = buffer_params; - delayed_reset.samples = samples; - delayed_reset.do_reset = true; + delayed_reset_.params = buffer_params; + delayed_reset_.samples = samples; + delayed_reset_.do_reset = true; device->task_cancel(); - pause_cond.notify_all(); + pause_cond_.notify_all(); } bool Session::draw_cpu(BufferParams &buffer_params, DeviceDrawParams &draw_params) { - thread_scoped_lock display_lock(display_mutex); + thread_scoped_lock display_lock(display_mutex_); /* first check we already rendered something */ if (display->draw_ready()) { @@ -331,7 +337,7 @@ bool Session::draw_cpu(BufferParams &buffer_params, DeviceDrawParams &draw_param buffer_params.height == display->params.height) { display->draw(device, draw_params); - if (display_outdated && (time_dt() - reset_time) > params.text_timeout) + if (display_outdated_ && (time_dt() - reset_time_) > params.text_timeout) return false; return true; @@ -345,46 +351,46 @@ bool Session::steal_tile(RenderTile &rtile, Device *tile_device, thread_scoped_l { /* Devices that can get their tiles stolen don't steal tiles themselves. * Additionally, if there are no stealable tiles in flight, give up here. */ - if (tile_device->info.type == DEVICE_CPU || stealable_tiles == 0) { + if (tile_device->info.type == DEVICE_CPU || stealable_tiles_ == 0) { return false; } /* Wait until no other thread is trying to steal a tile. */ - while (tile_stealing_state != NOT_STEALING && stealable_tiles > 0) { + while (tile_stealing_state_ != NOT_STEALING && stealable_tiles_ > 0) { /* Someone else is currently trying to get a tile. * Wait on the condition variable and try later. */ - tile_steal_cond.wait(tile_lock); + tile_steal_cond_.wait(tile_lock); } /* If another thread stole the last stealable tile in the meantime, give up. */ - if (stealable_tiles == 0) { + if (stealable_tiles_ == 0) { return false; } /* There are stealable tiles in flight, so signal that one should be released. */ - tile_stealing_state = WAITING_FOR_TILE; + tile_stealing_state_ = WAITING_FOR_TILE; /* Wait until a device notices the signal and releases its tile. */ - while (tile_stealing_state != GOT_TILE && stealable_tiles > 0) { - tile_steal_cond.wait(tile_lock); + while (tile_stealing_state_ != GOT_TILE && stealable_tiles_ > 0) { + tile_steal_cond_.wait(tile_lock); } /* If the last stealable tile finished on its own, give up. */ - if (tile_stealing_state != GOT_TILE) { - tile_stealing_state = NOT_STEALING; + if (tile_stealing_state_ != GOT_TILE) { + tile_stealing_state_ = NOT_STEALING; return false; } /* Successfully stole a tile, now move it to the new device. */ - rtile = stolen_tile; + rtile = stolen_tile_; rtile.buffers->buffer.move_device(tile_device); rtile.buffer = rtile.buffers->buffer.device_pointer; rtile.stealing_state = RenderTile::NO_STEALING; rtile.num_samples -= (rtile.sample - rtile.start_sample); rtile.start_sample = rtile.sample; - tile_stealing_state = NOT_STEALING; + tile_stealing_state_ = NOT_STEALING; /* Poke any threads which might be waiting for NOT_STEALING above. */ - tile_steal_cond.notify_one(); + tile_steal_cond_.notify_one(); return true; } @@ -394,7 +400,7 @@ bool Session::get_tile_stolen() /* If tile_stealing_state is WAITING_FOR_TILE, atomically set it to RELEASING_TILE * and return true. */ TileStealingState expected = WAITING_FOR_TILE; - return tile_stealing_state.compare_exchange_weak(expected, RELEASING_TILE); + return tile_stealing_state_.compare_exchange_weak(expected, RELEASING_TILE); } bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_types) @@ -406,7 +412,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ } } - thread_scoped_lock tile_lock(tile_mutex); + thread_scoped_lock tile_lock(tile_mutex_); /* get next tile from manager */ Tile *tile; @@ -423,7 +429,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ /* Wait for denoising tiles to become available */ if ((tile_types & RenderTile::DENOISE) && !progress.get_cancel() && tile_manager.has_tiles()) { - denoising_cond.wait(tile_lock); + denoising_cond_.wait(tile_lock); continue; } @@ -446,7 +452,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ } else { if (tile_device->info.type == DEVICE_CPU) { - stealable_tiles++; + stealable_tiles_++; rtile.stealing_state = RenderTile::CAN_BE_STOLEN; } @@ -515,7 +521,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ /* This will read any passes needed as input for baking. */ if (tile_manager.state.sample == tile_manager.range_start_sample) { { - thread_scoped_lock tile_lock(tile_mutex); + thread_scoped_lock tile_lock(tile_mutex_); read_bake_tile_cb(rtile); } rtile.buffers->buffer.copy_to_device(); @@ -533,7 +539,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ void Session::update_tile_sample(RenderTile &rtile) { - thread_scoped_lock tile_lock(tile_mutex); + thread_scoped_lock tile_lock(tile_mutex_); if (update_render_tile_cb) { if (params.progressive_refine == false) { @@ -548,25 +554,25 @@ void Session::update_tile_sample(RenderTile &rtile) void Session::release_tile(RenderTile &rtile, const bool need_denoise) { - thread_scoped_lock tile_lock(tile_mutex); + thread_scoped_lock tile_lock(tile_mutex_); if (rtile.stealing_state != RenderTile::NO_STEALING) { - stealable_tiles--; + stealable_tiles_--; if (rtile.stealing_state == RenderTile::WAS_STOLEN) { /* If the tile is being stolen, don't release it here - the new device will pick up where * the old one left off. */ - assert(tile_stealing_state == RELEASING_TILE); + assert(tile_stealing_state_ == RELEASING_TILE); assert(rtile.sample < rtile.start_sample + rtile.num_samples); - tile_stealing_state = GOT_TILE; - stolen_tile = rtile; - tile_steal_cond.notify_all(); + tile_stealing_state_ = GOT_TILE; + stolen_tile_ = rtile; + tile_steal_cond_.notify_all(); return; } - else if (stealable_tiles == 0) { + else if (stealable_tiles_ == 0) { /* If this was the last stealable tile, wake up any threads still waiting for one. */ - tile_steal_cond.notify_all(); + tile_steal_cond_.notify_all(); } } @@ -595,12 +601,12 @@ void Session::release_tile(RenderTile &rtile, const bool need_denoise) update_status_time(); /* Notify denoising thread that a tile was finished. */ - denoising_cond.notify_all(); + denoising_cond_.notify_all(); } void Session::map_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device) { - thread_scoped_lock tile_lock(tile_mutex); + thread_scoped_lock tile_lock(tile_mutex_); const int4 image_region = make_int4( tile_manager.state.buffer.full_x, @@ -677,7 +683,7 @@ void Session::map_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_de void Session::unmap_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device) { - thread_scoped_lock tile_lock(tile_mutex); + thread_scoped_lock tile_lock(tile_mutex_); device->unmap_neighbor_tiles(tile_device, neighbors); } @@ -685,8 +691,8 @@ void Session::run_cpu() { bool tiles_written = false; - last_update_time = time_dt(); - last_display_time = last_update_time; + last_update_time_ = time_dt(); + last_display_time_ = last_update_time_; while (!progress.get_cancel()) { const bool no_tiles = !run_update_for_next_iteration(); @@ -718,7 +724,7 @@ void Session::run_cpu() /* buffers mutex is locked entirely while rendering each * sample, and released/reacquired on each iteration to allow * reset and draw in between */ - thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock buffers_lock(buffers_mutex_); /* update status and timing */ update_status_time(); @@ -741,14 +747,14 @@ void Session::run_cpu() device->task_wait(); { - thread_scoped_lock reset_lock(delayed_reset.mutex); - thread_scoped_lock buffers_lock(buffers_mutex); - thread_scoped_lock display_lock(display_mutex); + thread_scoped_lock reset_lock(delayed_reset_.mutex); + thread_scoped_lock buffers_lock(buffers_mutex_); + thread_scoped_lock display_lock(display_mutex_); - if (delayed_reset.do_reset) { + if (delayed_reset_.do_reset) { /* reset rendering if request from main thread */ - delayed_reset.do_reset = false; - reset_(delayed_reset.params, delayed_reset.samples); + delayed_reset_.do_reset = false; + reset_(delayed_reset_.params, delayed_reset_.samples); } else if (need_copy_to_display_buffer) { /* Only copy to display_buffer if we do not reset, we don't @@ -783,7 +789,7 @@ void Session::run() /* reset number of rendered samples */ progress.reset_sample(); - if (device_use_gl) + if (device_use_gl_) run_gpu(); else run_cpu(); @@ -801,12 +807,12 @@ void Session::run() bool Session::run_update_for_next_iteration() { thread_scoped_lock scene_lock(scene->mutex); - thread_scoped_lock reset_lock(delayed_reset.mutex); + thread_scoped_lock reset_lock(delayed_reset_.mutex); - if (delayed_reset.do_reset) { - thread_scoped_lock buffers_lock(buffers_mutex); - reset_(delayed_reset.params, delayed_reset.samples); - delayed_reset.do_reset = false; + if (delayed_reset_.do_reset) { + thread_scoped_lock buffers_lock(buffers_mutex_); + reset_(delayed_reset_.params, delayed_reset_.samples); + delayed_reset_.do_reset = false; } const bool have_tiles = tile_manager.next(); @@ -829,35 +835,43 @@ bool Session::run_wait_for_work(bool no_tiles) return false; } - thread_scoped_lock pause_lock(pause_mutex); + thread_scoped_lock pause_lock(pause_mutex_); - if (!pause && !no_tiles) { + if (!pause_ && !no_tiles) { + /* Rendering is not paused and there is work to be done. No need to wait for anything. */ return false; } - update_status_time(pause, no_tiles); + update_status_time(pause_, no_tiles); - while (true) { + /* Only leave the loop when rendering is not paused. But even if the current render is un-paused + * but there is nothing to render keep waiting until new work is added. */ + while (!cancel_) { scoped_timer pause_timer; - pause_cond.wait(pause_lock); - if (pause) { - progress.add_skip_time(pause_timer, params.background); + + if (!pause_ && (!no_tiles || new_work_added_ || delayed_reset_.do_reset)) { + break; } - update_status_time(pause, no_tiles); - progress.set_update(); + /* Wait for either pause state changed, or extra samples added to render. */ + pause_cond_.wait(pause_lock); - if (!pause) { - break; + if (pause_) { + progress.add_skip_time(pause_timer, params.background); } + + update_status_time(pause_, no_tiles); + progress.set_update(); } + new_work_added_ = false; + return no_tiles; } bool Session::draw(BufferParams &buffer_params, DeviceDrawParams &draw_params) { - if (device_use_gl) + if (device_use_gl_) return draw_gpu(buffer_params, draw_params); else return draw_cpu(buffer_params, draw_params); @@ -866,7 +880,7 @@ bool Session::draw(BufferParams &buffer_params, DeviceDrawParams &draw_params) void Session::reset_(BufferParams &buffer_params, int samples) { if (buffers && buffer_params.modified(tile_manager.params)) { - gpu_draw_ready = false; + gpu_draw_ready_ = false; buffers->reset(buffer_params); if (display) { display->reset(buffer_params); @@ -874,8 +888,8 @@ void Session::reset_(BufferParams &buffer_params, int samples) } tile_manager.reset(buffer_params, samples); - stealable_tiles = 0; - tile_stealing_state = NOT_STEALING; + stealable_tiles_ = 0; + tile_stealing_state_ = NOT_STEALING; progress.reset_sample(); bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX; @@ -888,7 +902,7 @@ void Session::reset_(BufferParams &buffer_params, int samples) void Session::reset(BufferParams &buffer_params, int samples) { - if (device_use_gl) + if (device_use_gl_) reset_gpu(buffer_params, samples); else reset_cpu(buffer_params, samples); @@ -896,30 +910,37 @@ void Session::reset(BufferParams &buffer_params, int samples) void Session::set_samples(int samples) { - if (samples != params.samples) { - params.samples = samples; - tile_manager.set_samples(samples); + if (samples == params.samples) { + return; + } + + params.samples = samples; + tile_manager.set_samples(samples); - pause_cond.notify_all(); + { + thread_scoped_lock pause_lock(pause_mutex_); + new_work_added_ = true; } + + pause_cond_.notify_all(); } -void Session::set_pause(bool pause_) +void Session::set_pause(bool pause) { bool notify = false; { - thread_scoped_lock pause_lock(pause_mutex); + thread_scoped_lock pause_lock(pause_mutex_); if (pause != pause_) { - pause = pause_; + pause_ = pause; notify = true; } } - if (session_thread) { + if (session_thread_) { if (notify) { - pause_cond.notify_all(); + pause_cond_.notify_all(); } } else if (pause_) { @@ -932,7 +953,7 @@ void Session::set_denoising(const DenoiseParams &denoising) bool need_denoise = denoising.need_denoising_task(); /* Lock buffers so no denoising operation is triggered while the settings are changed here. */ - thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock buffers_lock(buffers_mutex_); params.denoising = denoising; if (!(params.device.denoisers & denoising.type)) { @@ -957,18 +978,18 @@ void Session::set_denoising_start_sample(int sample) if (sample != params.denoising.start_sample) { params.denoising.start_sample = sample; - pause_cond.notify_all(); + pause_cond_.notify_all(); } } void Session::wait() { - if (session_thread) { - session_thread->join(); - delete session_thread; + if (session_thread_) { + session_thread_->join(); + delete session_thread_; } - session_thread = NULL; + session_thread_ = NULL; } bool Session::update_scene() @@ -1099,7 +1120,7 @@ bool Session::render_need_denoise(bool &delayed) /* Avoid excessive denoising in viewport after reaching a certain amount of samples. */ delayed = (tile_manager.state.sample >= 20 && - (time_dt() - last_display_time) < params.progressive_update_timeout); + (time_dt() - last_display_time_) < params.progressive_update_timeout); return !delayed; } @@ -1197,10 +1218,10 @@ void Session::copy_to_display_buffer(int sample) /* set display to new size */ display->draw_set(task.w, task.h); - last_display_time = time_dt(); + last_display_time_ = time_dt(); } - display_outdated = false; + display_outdated_ = false; } bool Session::update_progressive_refine(bool cancel) @@ -1210,7 +1231,7 @@ bool Session::update_progressive_refine(bool cancel) double current_time = time_dt(); - if (current_time - last_update_time < params.progressive_update_timeout) { + if (current_time - last_update_time_ < params.progressive_update_timeout) { /* If last sample was processed, we need to write buffers anyway. */ if (!write && sample != 1) return false; @@ -1241,7 +1262,7 @@ bool Session::update_progressive_refine(bool cancel) } } - last_update_time = current_time; + last_update_time_ = current_time; return write; } diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index bc3b8366c05..05025c10f9c 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -174,7 +174,7 @@ class Session { bool do_reset; BufferParams params; int samples; - } delayed_reset; + } delayed_reset_; void run(); @@ -207,38 +207,41 @@ class Session { void map_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device); void unmap_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device); - bool device_use_gl; + bool device_use_gl_; - thread *session_thread; + thread *session_thread_; - volatile bool display_outdated; + volatile bool display_outdated_; - volatile bool gpu_draw_ready; - volatile bool gpu_need_display_buffer_update; - thread_condition_variable gpu_need_display_buffer_update_cond; + volatile bool gpu_draw_ready_; + volatile bool gpu_need_display_buffer_update_; + thread_condition_variable gpu_need_display_buffer_update_cond_; - bool pause; - thread_condition_variable pause_cond; - thread_mutex pause_mutex; - thread_mutex tile_mutex; - thread_mutex buffers_mutex; - thread_mutex display_mutex; - thread_condition_variable denoising_cond; - thread_condition_variable tile_steal_cond; + bool pause_; + bool cancel_; + bool new_work_added_; - double reset_time; - double last_update_time; - double last_display_time; + thread_condition_variable pause_cond_; + thread_mutex pause_mutex_; + thread_mutex tile_mutex_; + thread_mutex buffers_mutex_; + thread_mutex display_mutex_; + thread_condition_variable denoising_cond_; + thread_condition_variable tile_steal_cond_; - RenderTile stolen_tile; + double reset_time_; + double last_update_time_; + double last_display_time_; + + RenderTile stolen_tile_; typedef enum { NOT_STEALING, /* There currently is no tile stealing in progress. */ WAITING_FOR_TILE, /* A device is waiting for another device to release a tile. */ RELEASING_TILE, /* A device has releasing a stealable tile. */ GOT_TILE /* A device has released a stealable tile, which is now stored in stolen_tile. */ } TileStealingState; - std::atomic<TileStealingState> tile_stealing_state; - int stealable_tiles; + std::atomic<TileStealingState> tile_stealing_state_; + int stealable_tiles_; /* progressive refine */ bool update_progressive_refine(bool cancel); diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index d7c8f81ccfe..29d14700efd 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -157,6 +157,14 @@ class Shader : public Node { void tag_update(Scene *scene); void tag_used(Scene *scene); + /* Return true when either of the surface or displacement socket of the output node is linked. + * This should be used to ensure that surface attributes are also requested even when only the + * displacement socket is linked. */ + bool has_surface_link() const + { + return has_surface || has_displacement; + } + bool need_update_geometry() const; }; |