diff options
Diffstat (limited to 'intern/cycles/render/geometry.cpp')
-rw-r--r-- | intern/cycles/render/geometry.cpp | 583 |
1 files changed, 402 insertions, 181 deletions
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 894adafa6e6..a63fc620c69 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -52,14 +52,14 @@ NODE_ABSTRACT_DEFINE(Geometry) SOCKET_UINT(motion_steps, "Motion Steps", 3); SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false); + SOCKET_NODE_ARRAY(used_shaders, "Shaders", &Shader::node_type); return type; } Geometry::Geometry(const NodeType *node_type, const Type type) - : Node(node_type), type(type), attributes(this, ATTR_PRIM_GEOMETRY) + : Node(node_type), geometry_type(type), attributes(this, ATTR_PRIM_GEOMETRY) { - need_update = true; need_update_rebuild = false; transform_applied = false; @@ -81,9 +81,11 @@ Geometry::~Geometry() delete bvh; } -void Geometry::clear() +void Geometry::clear(bool preserve_shaders) { - used_shaders.clear(); + if (!preserve_shaders) + used_shaders.clear(); + transform_applied = false; transform_negative_scaled = false; transform_normal = transform_identity(); @@ -97,9 +99,11 @@ bool Geometry::need_attribute(Scene *scene, AttributeStandard std) if (scene->need_global_attribute(std)) return true; - foreach (Shader *shader, used_shaders) + foreach (Node *node, used_shaders) { + Shader *shader = static_cast<Shader *>(node); if (shader->attributes.find(std)) return true; + } return false; } @@ -109,13 +113,27 @@ bool Geometry::need_attribute(Scene * /*scene*/, ustring name) if (name == ustring()) return false; - foreach (Shader *shader, used_shaders) + foreach (Node *node, used_shaders) { + Shader *shader = static_cast<Shader *>(node); if (shader->attributes.find(name)) return true; + } return false; } +AttributeRequestSet Geometry::needed_attributes() +{ + AttributeRequestSet result; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast<Shader *>(node); + result.add(shader->attributes); + } + + return result; +} + float Geometry::motion_time(int step) const { return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f; @@ -159,8 +177,9 @@ bool Geometry::is_instanced() const bool Geometry::has_true_displacement() const { - foreach (Shader *shader, used_shaders) { - if (shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) { + foreach (Node *node, used_shaders) { + Shader *shader = static_cast<Shader *>(node); + if (shader->has_displacement && shader->get_displacement_method() != DISPLACE_BUMP) { return true; } } @@ -186,7 +205,7 @@ void Geometry::compute_bvh( msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); Object object; - object.geometry = this; + object.set_geometry(this); vector<Geometry *> geometry; geometry.push_back(this); @@ -220,7 +239,7 @@ void Geometry::compute_bvh( } } - need_update = false; + clear_modified(); need_update_rebuild = false; } @@ -242,16 +261,18 @@ bool Geometry::has_voxel_attributes() const void Geometry::tag_update(Scene *scene, bool rebuild) { - need_update = true; + tag_modified(); if (rebuild) { need_update_rebuild = true; scene->light_manager->need_update = true; } else { - foreach (Shader *shader, used_shaders) + foreach (Node *node, used_shaders) { + Shader *shader = static_cast<Shader *>(node); if (shader->has_surface_emission) scene->light_manager->need_update = true; + } } scene->geometry_manager->need_update = true; @@ -305,15 +326,12 @@ void GeometryManager::update_osl_attributes(Device *device, } /* find geometry attributes */ - size_t j; - - for (j = 0; j < scene->geometry.size(); j++) - if (scene->geometry[j] == object->geometry) - break; + size_t j = object->geometry->index; + assert(j < scene->geometry.size() && scene->geometry[j] == object->geometry); AttributeRequestSet &attributes = geom_attributes[j]; - /* set object attributes */ + /* set mesh attributes */ foreach (AttributeRequest &req, attributes.requests) { OSLGlobals::Attribute osl_attr; @@ -375,10 +393,68 @@ void GeometryManager::update_osl_attributes(Device *device, #endif } +/* Generate a normal attribute map entry from an attribute descriptor. */ +static void emit_attribute_map_entry( + uint4 *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc) +{ + attr_map[index].x = id; + attr_map[index].y = desc.element; + attr_map[index].z = as_uint(desc.offset); + + if (type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if (type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else if (type == TypeFloat2) + attr_map[index].w = NODE_ATTR_FLOAT2; + else if (type == TypeFloat4) + attr_map[index].w = NODE_ATTR_FLOAT4; + else if (type == TypeRGBA) + attr_map[index].w = NODE_ATTR_RGBA; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + + attr_map[index].w |= desc.flags << 8; +} + +/* Generate an attribute map end marker, optionally including a link to another map. + * Links are used to connect object attribute maps to mesh attribute maps. */ +static void emit_attribute_map_terminator(uint4 *attr_map, int index, bool chain, uint chain_link) +{ + for (int j = 0; j < ATTR_PRIM_TYPES; j++) { + attr_map[index + j].x = ATTR_STD_NONE; + attr_map[index + j].y = chain; /* link is valid flag */ + attr_map[index + j].z = chain ? chain_link + j : 0; /* link to the correct sub-entry */ + attr_map[index + j].w = 0; + } +} + +/* Generate all necessary attribute map entries from the attribute request. */ +static void emit_attribute_mapping( + uint4 *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom) +{ + uint id; + + if (req.std == ATTR_STD_NONE) + id = scene->shader_manager->get_attribute_id(req.name); + else + id = scene->shader_manager->get_attribute_id(req.std); + + emit_attribute_map_entry(attr_map, index, id, req.type, req.desc); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->get_num_subd_faces()) { + emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc); + } + } +} + void GeometryManager::update_svm_attributes(Device *, DeviceScene *dscene, Scene *scene, - vector<AttributeRequestSet> &geom_attributes) + vector<AttributeRequestSet> &geom_attributes, + vector<AttributeRequestSet> &object_attributes) { /* for SVM, the attributes_map table is used to lookup the offset of an * attribute, based on a unique shader attribute id. */ @@ -392,6 +468,19 @@ void GeometryManager::update_svm_attributes(Device *, attr_map_size += (geom_attributes[i].size() + 1) * ATTR_PRIM_TYPES; } + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + + /* only allocate a table for the object if it actually has attributes */ + if (object_attributes[i].size() == 0) { + object->attr_map_offset = 0; + } + else { + object->attr_map_offset = attr_map_size; + attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES; + } + } + if (attr_map_size == 0) return; @@ -403,69 +492,31 @@ void GeometryManager::update_svm_attributes(Device *, Geometry *geom = scene->geometry[i]; AttributeRequestSet &attributes = geom_attributes[i]; - /* set object attributes */ + /* set geometry attributes */ int index = geom->attr_map_offset; foreach (AttributeRequest &req, attributes.requests) { - uint id; - - if (req.std == ATTR_STD_NONE) - id = scene->shader_manager->get_attribute_id(req.name); - else - id = scene->shader_manager->get_attribute_id(req.std); - - attr_map[index].x = id; - attr_map[index].y = req.desc.element; - attr_map[index].z = as_uint(req.desc.offset); + emit_attribute_mapping(attr_map, index, scene, req, geom); + index += ATTR_PRIM_TYPES; + } - if (req.type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else if (req.type == TypeDesc::TypeMatrix) - attr_map[index].w = NODE_ATTR_MATRIX; - else if (req.type == TypeFloat2) - attr_map[index].w = NODE_ATTR_FLOAT2; - else if (req.type == TypeRGBA) - attr_map[index].w = NODE_ATTR_RGBA; - else - attr_map[index].w = NODE_ATTR_FLOAT3; + emit_attribute_map_terminator(attr_map, index, false, 0); + } - attr_map[index].w |= req.desc.flags << 8; + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + AttributeRequestSet &attributes = object_attributes[i]; - index++; + /* set object attributes */ + if (attributes.size() > 0) { + int index = object->attr_map_offset; - if (geom->type == Geometry::MESH) { - Mesh *mesh = static_cast<Mesh *>(geom); - if (mesh->subd_faces.size()) { - attr_map[index].x = id; - attr_map[index].y = req.subd_desc.element; - attr_map[index].z = as_uint(req.subd_desc.offset); - - if (req.subd_type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else if (req.subd_type == TypeDesc::TypeMatrix) - attr_map[index].w = NODE_ATTR_MATRIX; - else if (req.subd_type == TypeFloat2) - attr_map[index].w = NODE_ATTR_FLOAT2; - else if (req.subd_type == TypeRGBA) - attr_map[index].w = NODE_ATTR_RGBA; - else - attr_map[index].w = NODE_ATTR_FLOAT3; - - attr_map[index].w |= req.subd_desc.flags << 8; - } + foreach (AttributeRequest &req, attributes.requests) { + emit_attribute_mapping(attr_map, index, scene, req, object->geometry); + index += ATTR_PRIM_TYPES; } - index++; - } - - /* terminator */ - for (int j = 0; j < ATTR_PRIM_TYPES; j++) { - attr_map[index].x = ATTR_STD_NONE; - attr_map[index].y = 0; - attr_map[index].z = 0; - attr_map[index].w = 0; - - index++; + emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset); } } @@ -505,19 +556,19 @@ static void update_attribute_element_size(Geometry *geom, } } -static void update_attribute_element_offset(Geometry *geom, - device_vector<float> &attr_float, - size_t &attr_float_offset, - device_vector<float2> &attr_float2, - size_t &attr_float2_offset, - device_vector<float4> &attr_float3, - size_t &attr_float3_offset, - device_vector<uchar4> &attr_uchar4, - size_t &attr_uchar4_offset, - Attribute *mattr, - AttributePrimitive prim, - TypeDesc &type, - AttributeDescriptor &desc) +void GeometryManager::update_attribute_element_offset(Geometry *geom, + device_vector<float> &attr_float, + size_t &attr_float_offset, + device_vector<float2> &attr_float2, + size_t &attr_float2_offset, + device_vector<float4> &attr_float3, + size_t &attr_float3_offset, + device_vector<uchar4> &attr_uchar4, + size_t &attr_uchar4_offset, + Attribute *mattr, + AttributePrimitive prim, + TypeDesc &type, + AttributeDescriptor &desc) { if (mattr) { /* store element and type */ @@ -589,7 +640,7 @@ static void update_attribute_element_offset(Geometry *geom, /* mesh vertex/curve index is global, not per object, so we sneak * a correction for that in here */ - if (geom->type == Geometry::MESH) { + if (geom->is_mesh()) { Mesh *mesh = static_cast<Mesh *>(geom); if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && desc.flags & ATTR_SUBDIVIDED) { @@ -613,7 +664,7 @@ static void update_attribute_element_offset(Geometry *geom, offset -= mesh->corner_offset; } } - else if (geom->type == Geometry::HAIR) { + else if (geom->is_hair()) { Hair *hair = static_cast<Hair *>(geom); if (element == ATTR_ELEMENT_CURVE) offset -= hair->prim_offset; @@ -645,13 +696,48 @@ void GeometryManager::device_update_attributes(Device *device, for (size_t i = 0; i < scene->geometry.size(); i++) { Geometry *geom = scene->geometry[i]; + geom->index = i; scene->need_global_attributes(geom_attributes[i]); - foreach (Shader *shader, geom->used_shaders) { + foreach (Node *node, geom->get_used_shaders()) { + Shader *shader = static_cast<Shader *>(node); geom_attributes[i].add(shader->attributes); } } + /* convert object attributes to use the same data structures as geometry ones */ + vector<AttributeRequestSet> object_attributes(scene->objects.size()); + vector<AttributeSet> object_attribute_values; + + object_attribute_values.reserve(scene->objects.size()); + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + Geometry *geom = object->geometry; + size_t geom_idx = geom->index; + + assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom); + + object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY)); + + AttributeRequestSet &geom_requests = geom_attributes[geom_idx]; + AttributeRequestSet &attributes = object_attributes[i]; + AttributeSet &values = object_attribute_values[i]; + + for (size_t j = 0; j < object->attributes.size(); j++) { + ParamValue ¶m = object->attributes[j]; + + /* add attributes that are requested and not already handled by the mesh */ + if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) { + attributes.add(param.name()); + + Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT); + assert(param.datasize() == attr->buffer.size()); + memcpy(attr->buffer.data(), param.data(), param.datasize()); + } + } + } + /* mesh attribute are stored in a single array per data type. here we fill * those arrays, and set the offset and element type to create attribute * maps next */ @@ -663,6 +749,7 @@ void GeometryManager::device_update_attributes(Device *device, size_t attr_float2_size = 0; size_t attr_float3_size = 0; size_t attr_uchar4_size = 0; + for (size_t i = 0; i < scene->geometry.size(); i++) { Geometry *geom = scene->geometry[i]; AttributeRequestSet &attributes = geom_attributes[i]; @@ -677,7 +764,7 @@ void GeometryManager::device_update_attributes(Device *device, &attr_float3_size, &attr_uchar4_size); - if (geom->type == Geometry::MESH) { + if (geom->is_mesh()) { Mesh *mesh = static_cast<Mesh *>(geom); Attribute *subd_attr = mesh->subd_attributes.find(req); @@ -692,6 +779,20 @@ void GeometryManager::device_update_attributes(Device *device, } } + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + + foreach (Attribute &attr, object_attribute_values[i].attributes) { + update_attribute_element_size(object->geometry, + &attr, + ATTR_PRIM_GEOMETRY, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_uchar4_size); + } + } + dscene->attributes_float.alloc(attr_float_size); dscene->attributes_float2.alloc(attr_float2_size); dscene->attributes_float3.alloc(attr_float3_size); @@ -725,7 +826,7 @@ void GeometryManager::device_update_attributes(Device *device, req.type, req.desc); - if (geom->type == Geometry::MESH) { + if (geom->is_mesh()) { Mesh *mesh = static_cast<Mesh *>(geom); Attribute *subd_attr = mesh->subd_attributes.find(req); @@ -749,11 +850,42 @@ void GeometryManager::device_update_attributes(Device *device, } } + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + AttributeRequestSet &attributes = object_attributes[i]; + AttributeSet &values = object_attribute_values[i]; + + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = values.find(req); + + update_attribute_element_offset(object->geometry, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + attr, + ATTR_PRIM_GEOMETRY, + req.type, + req.desc); + + /* object attributes don't care about subdivision */ + req.subd_type = req.type; + req.subd_desc = req.desc; + + if (progress.get_cancel()) + return; + } + } + /* create attribute lookup maps */ if (scene->shader_manager->use_osl()) update_osl_attributes(device, scene, geom_attributes); - update_svm_attributes(device, dscene, scene, geom_attributes); + update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes); if (progress.get_cancel()) return; @@ -797,7 +929,7 @@ void GeometryManager::mesh_calc_offset(Scene *scene) size_t optix_prim_size = 0; foreach (Geometry *geom, scene->geometry) { - if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { Mesh *mesh = static_cast<Mesh *>(geom); mesh->vert_offset = vert_size; @@ -810,8 +942,8 @@ void GeometryManager::mesh_calc_offset(Scene *scene) vert_size += mesh->verts.size(); tri_size += mesh->num_triangles(); - if (mesh->subd_faces.size()) { - Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1]; + if (mesh->get_num_subd_faces()) { + Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1); patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; /* patch tables are stored in same array so include them in patch_size */ @@ -821,19 +953,19 @@ void GeometryManager::mesh_calc_offset(Scene *scene) } } - face_size += mesh->subd_faces.size(); + face_size += mesh->get_num_subd_faces(); corner_size += mesh->subd_face_corners.size(); mesh->optix_prim_offset = optix_prim_size; optix_prim_size += mesh->num_triangles(); } - else if (geom->type == Geometry::HAIR) { + else if (geom->is_hair()) { Hair *hair = static_cast<Hair *>(geom); hair->curvekey_offset = curve_key_size; hair->prim_offset = curve_size; - curve_key_size += hair->curve_keys.size(); + curve_key_size += hair->get_curve_keys().size(); curve_size += hair->num_curves(); hair->optix_prim_offset = optix_prim_size; @@ -855,14 +987,14 @@ void GeometryManager::device_update_mesh( size_t patch_size = 0; foreach (Geometry *geom, scene->geometry) { - if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { Mesh *mesh = static_cast<Mesh *>(geom); vert_size += mesh->verts.size(); tri_size += mesh->num_triangles(); - if (mesh->subd_faces.size()) { - Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1]; + if (mesh->get_num_subd_faces()) { + Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1); patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; /* patch tables are stored in same array so include them in patch_size */ @@ -872,10 +1004,10 @@ void GeometryManager::device_update_mesh( } } } - else if (geom->type == Geometry::HAIR) { + else if (geom->is_hair()) { Hair *hair = static_cast<Hair *>(geom); - curve_key_size += hair->curve_keys.size(); + curve_key_size += hair->get_curve_keys().size(); curve_size += hair->num_curves(); } } @@ -889,7 +1021,7 @@ void GeometryManager::device_update_mesh( * really use same semantic of arrays. */ foreach (Geometry *geom, scene->geometry) { - if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { Mesh *mesh = static_cast<Mesh *>(geom); for (size_t i = 0; i < mesh->num_triangles(); ++i) { tri_prim_index[i + mesh->prim_offset] = 3 * (i + mesh->prim_offset); @@ -917,7 +1049,7 @@ void GeometryManager::device_update_mesh( float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); foreach (Geometry *geom, scene->geometry) { - if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { Mesh *mesh = static_cast<Mesh *>(geom); mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); mesh->pack_normals(&vnormal[mesh->vert_offset]); @@ -949,7 +1081,7 @@ void GeometryManager::device_update_mesh( float4 *curves = dscene->curves.alloc(curve_size); foreach (Geometry *geom, scene->geometry) { - if (geom->type == Geometry::HAIR) { + if (geom->is_hair()) { Hair *hair = static_cast<Hair *>(geom); hair->pack_curves(scene, &curve_keys[hair->curvekey_offset], @@ -970,7 +1102,7 @@ void GeometryManager::device_update_mesh( uint *patch_data = dscene->patches.alloc(patch_size); foreach (Geometry *geom, scene->geometry) { - if (geom->type == Geometry::MESH) { + if (geom->is_mesh()) { Mesh *mesh = static_cast<Mesh *>(geom); mesh->pack_patches(&patch_data[mesh->patch_offset], mesh->vert_offset, @@ -993,7 +1125,7 @@ void GeometryManager::device_update_mesh( if (for_displacement) { float4 *prim_tri_verts = dscene->prim_tri_verts.alloc(tri_size * 3); foreach (Geometry *geom, scene->geometry) { - if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { Mesh *mesh = static_cast<Mesh *>(geom); for (size_t i = 0; i < mesh->num_triangles(); ++i) { Mesh::Triangle t = mesh->get_triangle(i); @@ -1106,6 +1238,12 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro return; } + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry({"device_update_preprocess", time}); + } + }); + progress.set_status("Updating Meshes Flags"); /* Update flags. */ @@ -1114,7 +1252,8 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro foreach (Geometry *geom, scene->geometry) { geom->has_volume = false; - foreach (const Shader *shader, geom->used_shaders) { + foreach (Node *node, geom->get_used_shaders()) { + Shader *shader = static_cast<Shader *>(node); if (shader->has_volume) { geom->has_volume = true; } @@ -1123,7 +1262,10 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro } } - if (need_update && geom->type == Geometry::VOLUME) { + /* Re-create volume mesh if we will rebuild or refit the BVH. Note we + * should only do it in that case, otherwise the BVH and mesh can go + * out of sync. */ + if (geom->is_modified() && geom->geometry_type == Geometry::VOLUME) { /* Create volume meshes if there is voxel data. */ if (!volume_images_updated) { progress.set_status("Updating Meshes Volume Bounds"); @@ -1135,7 +1277,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro create_volume_mesh(volume, progress); } - if (geom->type == Geometry::HAIR) { + if (geom->is_hair()) { /* Set curve shape, still a global scene setting for now. */ Hair *hair = static_cast<Hair *>(geom); hair->curve_shape = scene->params.hair_shape; @@ -1154,9 +1296,10 @@ void GeometryManager::device_update_displacement_images(Device *device, ImageManager *image_manager = scene->image_manager; set<int> bump_images; foreach (Geometry *geom, scene->geometry) { - if (geom->need_update) { - foreach (Shader *shader, geom->used_shaders) { - if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { + if (geom->is_modified()) { + foreach (Node *node, geom->get_used_shaders()) { + Shader *shader = static_cast<Shader *>(node); + if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) { continue; } foreach (ShaderNode *node, shader->graph->nodes) { @@ -1190,7 +1333,7 @@ void GeometryManager::device_update_volume_images(Device *device, Scene *scene, set<int> volume_images; foreach (Geometry *geom, scene->geometry) { - if (!geom->need_update) { + if (!geom->is_modified()) { continue; } @@ -1231,53 +1374,70 @@ void GeometryManager::device_update(Device *device, bool true_displacement_used = false; size_t total_tess_needed = 0; - foreach (Geometry *geom, scene->geometry) { - foreach (Shader *shader, geom->used_shaders) { - if (shader->need_update_geometry) - geom->need_update = true; - } + { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry({"device_update (normals)", time}); + } + }); - if (geom->need_update && (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME)) { - Mesh *mesh = static_cast<Mesh *>(geom); + foreach (Geometry *geom, scene->geometry) { + foreach (Node *node, geom->get_used_shaders()) { + Shader *shader = static_cast<Shader *>(node); + if (shader->need_update_geometry) + geom->tag_modified(); + } - /* Update normals. */ - mesh->add_face_normals(); - mesh->add_vertex_normals(); + if (geom->is_modified() && + (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) { + Mesh *mesh = static_cast<Mesh *>(geom); - if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { - mesh->add_undisplaced(); - } + /* Update normals. */ + mesh->add_face_normals(); + mesh->add_vertex_normals(); - /* Test if we need tessellation. */ - if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE && mesh->num_subd_verts == 0 && - mesh->subd_params) { - total_tess_needed++; - } + if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { + mesh->add_undisplaced(); + } - /* Test if we need displacement. */ - if (mesh->has_true_displacement()) { - true_displacement_used = true; - } + /* Test if we need tessellation. */ + if (mesh->need_tesselation()) { + total_tess_needed++; + } - if (progress.get_cancel()) - return; + /* Test if we need displacement. */ + if (mesh->has_true_displacement()) { + true_displacement_used = true; + } + + if (progress.get_cancel()) + return; + } } } /* Tessellate meshes that are using subdivision */ if (total_tess_needed) { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry( + {"device_update (adaptive subdivision)", time}); + } + }); + Camera *dicing_camera = scene->dicing_camera; + dicing_camera->set_screen_size_and_resolution( + dicing_camera->get_full_width(), dicing_camera->get_full_height(), 1); dicing_camera->update(scene); size_t i = 0; foreach (Geometry *geom, scene->geometry) { - if (!(geom->need_update && geom->type == Geometry::MESH)) { + if (!(geom->is_modified() && geom->is_mesh())) { continue; } Mesh *mesh = static_cast<Mesh *>(geom); - if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE && mesh->num_subd_verts == 0 && - mesh->subd_params) { + if (mesh->need_tesselation()) { string msg = "Tessellating "; if (mesh->name == "") msg += string_printf("%u/%u", (uint)(i + 1), (uint)total_tess_needed); @@ -1302,7 +1462,12 @@ void GeometryManager::device_update(Device *device, /* Update images needed for true displacement. */ bool old_need_object_flags_update = false; if (true_displacement_used) { - VLOG(1) << "Updating images used for true displacement."; + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry( + {"device_update (displacement: load images)", time}); + } + }); device_update_displacement_images(device, scene, progress); old_need_object_flags_update = scene->object_manager->need_flags_update; scene->object_manager->device_update_flags(device, dscene, scene, progress, false); @@ -1313,41 +1478,68 @@ void GeometryManager::device_update(Device *device, mesh_calc_offset(scene); if (true_displacement_used) { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry( + {"device_update (displacement: copy meshes to device)", time}); + } + }); device_update_mesh(device, dscene, scene, true, progress); } if (progress.get_cancel()) return; - device_update_attributes(device, dscene, scene, progress); - if (progress.get_cancel()) - return; + { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry({"device_update (attributes)", time}); + } + }); + device_update_attributes(device, dscene, scene, progress); + if (progress.get_cancel()) + return; + } /* Update displacement. */ - bool displacement_done = false; - size_t num_bvh = 0; BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, device->get_bvh_layout_mask()); + bool displacement_done = false; + size_t num_bvh = 0; - foreach (Geometry *geom, scene->geometry) { - if (geom->need_update) { - if (geom->type == Geometry::MESH) { - Mesh *mesh = static_cast<Mesh *>(geom); - if (displace(device, dscene, scene, mesh, progress)) { - displacement_done = true; - } + { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry({"device_update (displacement)", time}); } + }); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_modified()) { + if (geom->is_mesh()) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (displace(device, dscene, scene, mesh, progress)) { + displacement_done = true; + } + } - if (geom->need_build_bvh(bvh_layout)) { - num_bvh++; + if (geom->need_build_bvh(bvh_layout)) { + num_bvh++; + } } - } - if (progress.get_cancel()) - return; + if (progress.get_cancel()) + return; + } } /* Device re-update after displacement. */ if (displacement_done) { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry( + {"device_update (displacement: attributes)", time}); + } + }); device_free(device, dscene); device_update_attributes(device, dscene, scene, progress); @@ -1355,22 +1547,29 @@ void GeometryManager::device_update(Device *device, return; } - TaskPool pool; + { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry({"device_update (build object BVHs)", time}); + } + }); + TaskPool pool; - size_t i = 0; - foreach (Geometry *geom, scene->geometry) { - if (geom->need_update) { - pool.push(function_bind( - &Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh)); - if (geom->need_build_bvh(bvh_layout)) { - i++; + size_t i = 0; + foreach (Geometry *geom, scene->geometry) { + if (geom->is_modified()) { + pool.push(function_bind( + &Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh)); + if (geom->need_build_bvh(bvh_layout)) { + i++; + } } } - } - TaskPool::Summary summary; - pool.wait_work(&summary); - VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report(); + TaskPool::Summary summary; + pool.wait_work(&summary); + VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report(); + } foreach (Shader *shader, scene->shaders) { shader->need_update_geometry = false; @@ -1380,21 +1579,43 @@ void GeometryManager::device_update(Device *device, bool motion_blur = need_motion == Scene::MOTION_BLUR; /* Update objects. */ - vector<Object *> volume_objects; - foreach (Object *object, scene->objects) { - object->compute_bounds(motion_blur); + { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry({"device_update (compute bounds)", time}); + } + }); + vector<Object *> volume_objects; + foreach (Object *object, scene->objects) { + object->compute_bounds(motion_blur); + } } if (progress.get_cancel()) return; - device_update_bvh(device, dscene, scene, progress); - if (progress.get_cancel()) - return; + { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry({"device_update (build scene BVH)", time}); + } + }); + device_update_bvh(device, dscene, scene, progress); + if (progress.get_cancel()) + return; + } - device_update_mesh(device, dscene, scene, false, progress); - if (progress.get_cancel()) - return; + { + scoped_callback_timer timer([scene](double time) { + if (scene->update_stats) { + scene->update_stats->geometry.times.add_entry( + {"device_update (copy meshes to device)", time}); + } + }); + device_update_mesh(device, dscene, scene, false, progress); + if (progress.get_cancel()) + return; + } need_update = false; |