From 475f9a3e23fcccfcac65a34537ddadd65fe4403f Mon Sep 17 00:00:00 2001 From: William Leeson Date: Thu, 20 Apr 2023 12:26:02 +0200 Subject: [PATCH] Cycles: Break up geometry.cpp and scene.cpp file into smaller pieces Scene.cpp and Geometry.cpp are large file it can be broken up into smaller easier to handle files. This change has been broken out from #105403 to make understanding the changes easier. geometry.cpp is broken up into: 1. geometry.cpp 2. geometry_attributes.cpp 3. geometry_bvh.cpp 4. geometry_mesh.cpp scene.h & scene.cpp is broken into: 1. scene.h 2. scene.cpp 3. devicescene.h 4. devicescene.cpp Pull Request: https://projects.blender.org/blender/blender/pulls/107079 --- intern/cycles/scene/CMakeLists.txt | 5 + intern/cycles/scene/devicescene.cpp | 64 ++ intern/cycles/scene/devicescene.h | 101 ++ intern/cycles/scene/geometry.cpp | 1151 +------------------ intern/cycles/scene/geometry.h | 32 + intern/cycles/scene/geometry_attributes.cpp | 722 ++++++++++++ intern/cycles/scene/geometry_bvh.cpp | 196 ++++ intern/cycles/scene/geometry_mesh.cpp | 223 ++++ intern/cycles/scene/scene.cpp | 55 +- intern/cycles/scene/scene.h | 92 +- 10 files changed, 1389 insertions(+), 1252 deletions(-) create mode 100644 intern/cycles/scene/devicescene.cpp create mode 100644 intern/cycles/scene/devicescene.h create mode 100644 intern/cycles/scene/geometry_attributes.cpp create mode 100644 intern/cycles/scene/geometry_bvh.cpp create mode 100644 intern/cycles/scene/geometry_mesh.cpp diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt index 759a25ab7cb..3fc972da75e 100644 --- a/intern/cycles/scene/CMakeLists.txt +++ b/intern/cycles/scene/CMakeLists.txt @@ -15,8 +15,12 @@ set(SRC camera.cpp colorspace.cpp constant_fold.cpp + devicescene.cpp film.cpp geometry.cpp + geometry_attributes.cpp + geometry_bvh.cpp + geometry_mesh.cpp hair.cpp image.cpp image_oiio.cpp @@ -55,6 +59,7 @@ set(SRC_HEADERS camera.h colorspace.h constant_fold.h + devicescene.h film.h geometry.h hair.h diff --git a/intern/cycles/scene/devicescene.cpp b/intern/cycles/scene/devicescene.cpp new file mode 100644 index 00000000000..8325c4855f5 --- /dev/null +++ b/intern/cycles/scene/devicescene.cpp @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "scene/devicescene.h" +#include "device/device.h" +#include "device/memory.h" + +CCL_NAMESPACE_BEGIN + +DeviceScene::DeviceScene(Device *device) + : bvh_nodes(device, "bvh_nodes", MEM_GLOBAL), + bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL), + object_node(device, "object_node", MEM_GLOBAL), + prim_type(device, "prim_type", MEM_GLOBAL), + prim_visibility(device, "prim_visibility", MEM_GLOBAL), + prim_index(device, "prim_index", MEM_GLOBAL), + prim_object(device, "prim_object", MEM_GLOBAL), + prim_time(device, "prim_time", MEM_GLOBAL), + tri_verts(device, "tri_verts", MEM_GLOBAL), + tri_shader(device, "tri_shader", MEM_GLOBAL), + tri_vnormal(device, "tri_vnormal", MEM_GLOBAL), + tri_vindex(device, "tri_vindex", MEM_GLOBAL), + tri_patch(device, "tri_patch", MEM_GLOBAL), + tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL), + curves(device, "curves", MEM_GLOBAL), + curve_keys(device, "curve_keys", MEM_GLOBAL), + curve_segments(device, "curve_segments", MEM_GLOBAL), + patches(device, "patches", MEM_GLOBAL), + points(device, "points", MEM_GLOBAL), + points_shader(device, "points_shader", MEM_GLOBAL), + objects(device, "objects", MEM_GLOBAL), + object_motion_pass(device, "object_motion_pass", MEM_GLOBAL), + object_motion(device, "object_motion", MEM_GLOBAL), + object_flag(device, "object_flag", MEM_GLOBAL), + object_volume_step(device, "object_volume_step", MEM_GLOBAL), + object_prim_offset(device, "object_prim_offset", MEM_GLOBAL), + camera_motion(device, "camera_motion", MEM_GLOBAL), + attributes_map(device, "attributes_map", MEM_GLOBAL), + attributes_float(device, "attributes_float", MEM_GLOBAL), + attributes_float2(device, "attributes_float2", MEM_GLOBAL), + attributes_float3(device, "attributes_float3", MEM_GLOBAL), + attributes_float4(device, "attributes_float4", MEM_GLOBAL), + attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL), + light_distribution(device, "light_distribution", MEM_GLOBAL), + lights(device, "lights", MEM_GLOBAL), + light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL), + light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL), + light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL), + light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL), + light_to_tree(device, "light_to_tree", MEM_GLOBAL), + object_to_tree(device, "object_to_tree", MEM_GLOBAL), + object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL), + triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL), + particles(device, "particles", MEM_GLOBAL), + svm_nodes(device, "svm_nodes", MEM_GLOBAL), + shaders(device, "shaders", MEM_GLOBAL), + lookup_table(device, "lookup_table", MEM_GLOBAL), + sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL), + ies_lights(device, "ies", MEM_GLOBAL) +{ + memset((void *)&data, 0, sizeof(data)); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/devicescene.h b/intern/cycles/scene/devicescene.h new file mode 100644 index 00000000000..250b3b86516 --- /dev/null +++ b/intern/cycles/scene/devicescene.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#ifndef __DEVICESCENE_H__ +#define __DEVICESCENE_H__ + +#include "device/device.h" +#include "device/memory.h" + +#include "util/types.h" +#include "util/vector.h" + +CCL_NAMESPACE_BEGIN + +class DeviceScene { + public: + /* BVH */ + device_vector bvh_nodes; + device_vector bvh_leaf_nodes; + device_vector object_node; + device_vector prim_type; + device_vector prim_visibility; + device_vector prim_index; + device_vector prim_object; + device_vector prim_time; + + /* mesh */ + device_vector tri_verts; + device_vector tri_shader; + device_vector tri_vnormal; + device_vector tri_vindex; + device_vector tri_patch; + device_vector tri_patch_uv; + + device_vector curves; + device_vector curve_keys; + device_vector curve_segments; + + device_vector patches; + + /* point-cloud */ + device_vector points; + device_vector points_shader; + + /* objects */ + device_vector objects; + device_vector object_motion_pass; + device_vector object_motion; + device_vector object_flag; + device_vector object_volume_step; + device_vector object_prim_offset; + + /* cameras */ + device_vector camera_motion; + + /* attributes */ + device_vector attributes_map; + device_vector attributes_float; + device_vector attributes_float2; + device_vector attributes_float3; + device_vector attributes_float4; + device_vector attributes_uchar4; + + /* lights */ + device_vector light_distribution; + device_vector lights; + device_vector light_background_marginal_cdf; + device_vector light_background_conditional_cdf; + + /* light tree */ + device_vector light_tree_nodes; + device_vector light_tree_emitters; + device_vector light_to_tree; + device_vector object_to_tree; + device_vector object_lookup_offset; + device_vector triangle_to_tree; + + /* particles */ + device_vector particles; + + /* shaders */ + device_vector svm_nodes; + device_vector shaders; + + /* lookup tables */ + device_vector lookup_table; + + /* integrator */ + device_vector sample_pattern_lut; + + /* IES lights */ + device_vector ies_lights; + + KernelData data; + + DeviceScene(Device *device); +}; + +CCL_NAMESPACE_END + +#endif /* __DEVICESCENE_H__ */ diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp index 58a9a97bf32..21d3b6a52a6 100644 --- a/intern/cycles/scene/geometry.cpp +++ b/intern/cycles/scene/geometry.cpp @@ -84,49 +84,6 @@ void Geometry::clear(bool preserve_shaders) tag_modified(); } -bool Geometry::need_attribute(Scene *scene, AttributeStandard std) -{ - if (std == ATTR_STD_NONE) - return false; - - if (scene->need_global_attribute(std)) - return true; - - foreach (Node *node, used_shaders) { - Shader *shader = static_cast(node); - if (shader->attributes.find(std)) - return true; - } - - return false; -} - -bool Geometry::need_attribute(Scene * /*scene*/, ustring name) -{ - if (name == ustring()) - return false; - - foreach (Node *node, used_shaders) { - Shader *shader = static_cast(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(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; @@ -182,89 +139,11 @@ bool Geometry::has_true_displacement() const return false; } -void Geometry::compute_bvh(Device *device, - DeviceScene *dscene, - SceneParams *params, - Progress *progress, - size_t n, - size_t total) -{ - if (progress->get_cancel()) - return; - - compute_bounds(); - - const BVHLayout bvh_layout = BVHParams::best_bvh_layout( - params->bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); - if (need_build_bvh(bvh_layout)) { - string msg = "Updating Geometry BVH "; - if (name.empty()) - msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); - else - msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); - - Object object; - - /* Ensure all visibility bits are set at the geometry level BVH. In - * the object level BVH is where actual visibility is tested. */ - object.set_is_shadow_catcher(true); - object.set_visibility(~0); - - object.set_geometry(this); - - vector geometry; - geometry.push_back(this); - vector objects; - objects.push_back(&object); - - if (bvh && !need_update_rebuild) { - progress->set_status(msg, "Refitting BVH"); - - bvh->replace_geometry(geometry, objects); - - device->build_bvh(bvh, *progress, true); - } - else { - progress->set_status(msg, "Building BVH"); - - BVHParams bparams; - bparams.use_spatial_split = params->use_bvh_spatial_split; - bparams.use_compact_structure = params->use_bvh_compact_structure; - bparams.bvh_layout = bvh_layout; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - params->use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = params->num_bvh_time_steps; - bparams.num_motion_curve_steps = params->num_bvh_time_steps; - bparams.num_motion_point_steps = params->num_bvh_time_steps; - bparams.bvh_type = params->bvh_type; - bparams.curve_subdivisions = params->curve_subdivisions(); - - delete bvh; - bvh = BVH::create(bparams, geometry, objects, device); - MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false); - } - } - - need_update_rebuild = false; - need_update_bvh_for_offset = false; -} - bool Geometry::has_motion_blur() const { return (use_motion_blur && attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)); } -bool Geometry::has_voxel_attributes() const -{ - foreach (const Attribute &attr, attributes.attributes) { - if (attr.element == ATTR_ELEMENT_VOXEL) { - return true; - } - } - - return false; -} - void Geometry::tag_update(Scene *scene, bool rebuild) { if (rebuild) { @@ -328,637 +207,62 @@ void GeometryManager::update_osl_globals(Device *device, Scene *scene) #endif } -/* Generate a normal attribute map entry from an attribute descriptor. */ -static void emit_attribute_map_entry(AttributeMap *attr_map, - size_t index, - uint64_t id, - TypeDesc type, - const AttributeDescriptor &desc) +static void update_device_flags_attribute(uint32_t &device_update_flags, + const AttributeSet &attributes) { - attr_map[index].id = id; - attr_map[index].element = desc.element; - attr_map[index].offset = as_uint(desc.offset); + foreach (const Attribute &attr, attributes.attributes) { + if (!attr.modified) { + continue; + } - if (type == TypeDesc::TypeFloat) - attr_map[index].type = NODE_ATTR_FLOAT; - else if (type == TypeDesc::TypeMatrix) - attr_map[index].type = NODE_ATTR_MATRIX; - else if (type == TypeFloat2) - attr_map[index].type = NODE_ATTR_FLOAT2; - else if (type == TypeFloat4) - attr_map[index].type = NODE_ATTR_FLOAT4; - else if (type == TypeRGBA) - attr_map[index].type = NODE_ATTR_RGBA; - else - attr_map[index].type = NODE_ATTR_FLOAT3; + AttrKernelDataType kernel_type = Attribute::kernel_type(attr); - attr_map[index].flags = desc.flags; -} - -/* 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(AttributeMap *attr_map, - size_t index, - bool chain, - uint chain_link) -{ - for (int j = 0; j < ATTR_PRIM_TYPES; j++) { - attr_map[index + j].id = ATTR_STD_NONE; - attr_map[index + j].element = chain; /* link is valid flag */ - attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */ - attr_map[index + j].type = 0; - attr_map[index + j].flags = 0; - } -} - -/* Generate all necessary attribute map entries from the attribute request. */ -static void emit_attribute_mapping( - AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom) -{ - emit_attribute_map_entry(attr_map, index, id, req.type, req.desc); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - if (mesh->get_num_subd_faces()) { - emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc); + switch (kernel_type) { + case AttrKernelDataType::FLOAT: { + device_update_flags |= ATTR_FLOAT_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT2: { + device_update_flags |= ATTR_FLOAT2_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT3: { + device_update_flags |= ATTR_FLOAT3_MODIFIED; + break; + } + case AttrKernelDataType::FLOAT4: { + device_update_flags |= ATTR_FLOAT4_MODIFIED; + break; + } + case AttrKernelDataType::UCHAR4: { + device_update_flags |= ATTR_UCHAR4_MODIFIED; + break; + } + case AttrKernelDataType::NUM: { + break; + } } } } -void GeometryManager::update_svm_attributes(Device *, - DeviceScene *dscene, - Scene *scene, - vector &geom_attributes, - vector &object_attributes) +static void update_attribute_realloc_flags(uint32_t &device_update_flags, + const AttributeSet &attributes) { - /* for SVM, the attributes_map table is used to lookup the offset of an - * attribute, based on a unique shader attribute id. */ - - /* compute array stride */ - size_t attr_map_size = 0; - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - geom->attr_map_offset = attr_map_size; - -#ifdef WITH_OSL - size_t attr_count = 0; - foreach (AttributeRequest &req, geom_attributes[i].requests) { - if (req.std != ATTR_STD_NONE && - scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std) - attr_count += 2; - else - attr_count += 1; - } -#else - const size_t attr_count = geom_attributes[i].size(); -#endif - - attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES; + if (attributes.modified(AttrKernelDataType::FLOAT)) { + device_update_flags |= ATTR_FLOAT_NEEDS_REALLOC; } - - 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 (attributes.modified(AttrKernelDataType::FLOAT2)) { + device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC; } - - if (attr_map_size == 0) - return; - - if (!dscene->attributes_map.need_realloc()) { - return; + if (attributes.modified(AttrKernelDataType::FLOAT3)) { + device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC; } - - /* create attribute map */ - AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size); - memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map)); - - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - AttributeRequestSet &attributes = geom_attributes[i]; - - /* set geometry attributes */ - size_t index = geom->attr_map_offset; - - foreach (AttributeRequest &req, attributes.requests) { - uint64_t 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_mapping(attr_map, index, id, req, geom); - index += ATTR_PRIM_TYPES; - -#ifdef WITH_OSL - /* Some standard attributes are explicitly referenced via their standard ID, so add those - * again in case they were added under a different attribute ID. */ - if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) { - emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom); - index += ATTR_PRIM_TYPES; - } -#endif - } - - emit_attribute_map_terminator(attr_map, index, false, 0); + if (attributes.modified(AttrKernelDataType::FLOAT4)) { + device_update_flags |= ATTR_FLOAT4_NEEDS_REALLOC; } - - for (size_t i = 0; i < scene->objects.size(); i++) { - Object *object = scene->objects[i]; - AttributeRequestSet &attributes = object_attributes[i]; - - /* set object attributes */ - if (attributes.size() > 0) { - size_t index = object->attr_map_offset; - - foreach (AttributeRequest &req, attributes.requests) { - uint64_t 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_mapping(attr_map, index, id, req, object->geometry); - index += ATTR_PRIM_TYPES; - } - - emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset); - } + if (attributes.modified(AttrKernelDataType::UCHAR4)) { + device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC; } - - /* copy to device */ - dscene->attributes_map.copy_to_device(); -} - -static void update_attribute_element_size(Geometry *geom, - Attribute *mattr, - AttributePrimitive prim, - size_t *attr_float_size, - size_t *attr_float2_size, - size_t *attr_float3_size, - size_t *attr_float4_size, - size_t *attr_uchar4_size) -{ - if (mattr) { - size_t size = mattr->element_size(geom, prim); - - if (mattr->element == ATTR_ELEMENT_VOXEL) { - /* pass */ - } - else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - *attr_uchar4_size += size; - } - else if (mattr->type == TypeDesc::TypeFloat) { - *attr_float_size += size; - } - else if (mattr->type == TypeFloat2) { - *attr_float2_size += size; - } - else if (mattr->type == TypeDesc::TypeMatrix) { - *attr_float4_size += size * 4; - } - else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { - *attr_float4_size += size; - } - else { - *attr_float3_size += size; - } - } -} - -void GeometryManager::update_attribute_element_offset(Geometry *geom, - device_vector &attr_float, - size_t &attr_float_offset, - device_vector &attr_float2, - size_t &attr_float2_offset, - device_vector &attr_float3, - size_t &attr_float3_offset, - device_vector &attr_float4, - size_t &attr_float4_offset, - device_vector &attr_uchar4, - size_t &attr_uchar4_offset, - Attribute *mattr, - AttributePrimitive prim, - TypeDesc &type, - AttributeDescriptor &desc) -{ - if (mattr) { - /* store element and type */ - desc.element = mattr->element; - desc.flags = mattr->flags; - type = mattr->type; - - /* store attribute data in arrays */ - size_t size = mattr->element_size(geom, prim); - - AttributeElement &element = desc.element; - int &offset = desc.offset; - - if (mattr->element == ATTR_ELEMENT_VOXEL) { - /* store slot in offset value */ - ImageHandle &handle = mattr->data_voxel(); - offset = handle.svm_slot(); - } - else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - uchar4 *data = mattr->data_uchar4(); - offset = attr_uchar4_offset; - - assert(attr_uchar4.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_uchar4[offset + k] = data[k]; - } - attr_uchar4.tag_modified(); - } - attr_uchar4_offset += size; - } - else if (mattr->type == TypeDesc::TypeFloat) { - float *data = mattr->data_float(); - offset = attr_float_offset; - - assert(attr_float.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float[offset + k] = data[k]; - } - attr_float.tag_modified(); - } - attr_float_offset += size; - } - else if (mattr->type == TypeFloat2) { - float2 *data = mattr->data_float2(); - offset = attr_float2_offset; - - assert(attr_float2.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float2[offset + k] = data[k]; - } - attr_float2.tag_modified(); - } - attr_float2_offset += size; - } - else if (mattr->type == TypeDesc::TypeMatrix) { - Transform *tfm = mattr->data_transform(); - offset = attr_float4_offset; - - assert(attr_float4.size() >= offset + size * 3); - if (mattr->modified) { - for (size_t k = 0; k < size * 3; k++) { - attr_float4[offset + k] = (&tfm->x)[k]; - } - attr_float4.tag_modified(); - } - attr_float4_offset += size * 3; - } - else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { - float4 *data = mattr->data_float4(); - offset = attr_float4_offset; - - assert(attr_float4.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float4[offset + k] = data[k]; - } - attr_float4.tag_modified(); - } - attr_float4_offset += size; - } - else { - float3 *data = mattr->data_float3(); - offset = attr_float3_offset; - - assert(attr_float3.size() >= offset + size); - if (mattr->modified) { - for (size_t k = 0; k < size; k++) { - attr_float3[offset + k] = data[k]; - } - attr_float3.tag_modified(); - } - attr_float3_offset += size; - } - - /* mesh vertex/curve index is global, not per object, so we sneak - * a correction for that in here */ - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && - desc.flags & ATTR_SUBDIVIDED) { - /* Indices for subdivided attributes are retrieved - * from patch table so no need for correction here. */ - } - else if (element == ATTR_ELEMENT_VERTEX) - offset -= mesh->vert_offset; - else if (element == ATTR_ELEMENT_VERTEX_MOTION) - offset -= mesh->vert_offset; - else if (element == ATTR_ELEMENT_FACE) { - if (prim == ATTR_PRIM_GEOMETRY) - offset -= mesh->prim_offset; - else - offset -= mesh->face_offset; - } - else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { - if (prim == ATTR_PRIM_GEOMETRY) - offset -= 3 * mesh->prim_offset; - else - offset -= mesh->corner_offset; - } - } - else if (geom->is_hair()) { - Hair *hair = static_cast(geom); - if (element == ATTR_ELEMENT_CURVE) - offset -= hair->prim_offset; - else if (element == ATTR_ELEMENT_CURVE_KEY) - offset -= hair->curve_key_offset; - else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) - offset -= hair->curve_key_offset; - } - else if (geom->is_pointcloud()) { - if (element == ATTR_ELEMENT_VERTEX) - offset -= geom->prim_offset; - else if (element == ATTR_ELEMENT_VERTEX_MOTION) - offset -= geom->prim_offset; - } - } - else { - /* attribute not found */ - desc.element = ATTR_ELEMENT_NONE; - desc.offset = 0; - } -} - -void GeometryManager::device_update_attributes(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - progress.set_status("Updating Mesh", "Computing attributes"); - - /* gather per mesh requested attributes. as meshes may have multiple - * shaders assigned, this merges the requested attributes that have - * been set per shader by the shader manager */ - vector geom_attributes(scene->geometry.size()); - - 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 (Node *node, geom->get_used_shaders()) { - Shader *shader = static_cast(node); - geom_attributes[i].add(shader->attributes); - } - - if (geom->is_hair() && static_cast(geom)->need_shadow_transparency()) { - geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY); - } - } - - /* convert object attributes to use the same data structures as geometry ones */ - vector object_attributes(scene->objects.size()); - vector 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 */ - - /* Pre-allocate attributes to avoid arrays re-allocation which would - * take 2x of overall attribute memory usage. - */ - size_t attr_float_size = 0; - size_t attr_float2_size = 0; - size_t attr_float3_size = 0; - size_t attr_float4_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]; - foreach (AttributeRequest &req, attributes.requests) { - Attribute *attr = geom->attributes.find(req); - - update_attribute_element_size(geom, - attr, - ATTR_PRIM_GEOMETRY, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_float4_size, - &attr_uchar4_size); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - Attribute *subd_attr = mesh->subd_attributes.find(req); - - update_attribute_element_size(mesh, - subd_attr, - ATTR_PRIM_SUBD, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_float4_size, - &attr_uchar4_size); - } - } - } - - 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_float4_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); - dscene->attributes_float4.alloc(attr_float4_size); - dscene->attributes_uchar4.alloc(attr_uchar4_size); - - /* The order of those flags needs to match that of AttrKernelDataType. */ - const bool attributes_need_realloc[AttrKernelDataType::NUM] = { - dscene->attributes_float.need_realloc(), - dscene->attributes_float2.need_realloc(), - dscene->attributes_float3.need_realloc(), - dscene->attributes_float4.need_realloc(), - dscene->attributes_uchar4.need_realloc(), - }; - - size_t attr_float_offset = 0; - size_t attr_float2_offset = 0; - size_t attr_float3_offset = 0; - size_t attr_float4_offset = 0; - size_t attr_uchar4_offset = 0; - - /* Fill in attributes. */ - for (size_t i = 0; i < scene->geometry.size(); i++) { - Geometry *geom = scene->geometry[i]; - AttributeRequestSet &attributes = geom_attributes[i]; - - /* todo: we now store std and name attributes from requests even if - * they actually refer to the same mesh attributes, optimize */ - foreach (AttributeRequest &req, attributes.requests) { - Attribute *attr = geom->attributes.find(req); - - if (attr) { - /* force a copy if we need to reallocate all the data */ - attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; - } - - update_attribute_element_offset(geom, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_float4, - attr_float4_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - attr, - ATTR_PRIM_GEOMETRY, - req.type, - req.desc); - - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - Attribute *subd_attr = mesh->subd_attributes.find(req); - - if (subd_attr) { - /* force a copy if we need to reallocate all the data */ - subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)]; - } - - update_attribute_element_offset(mesh, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_float4, - attr_float4_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - subd_attr, - ATTR_PRIM_SUBD, - req.subd_type, - req.subd_desc); - } - - if (progress.get_cancel()) - return; - } - } - - 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); - - if (attr) { - attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; - } - - 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_float4, - attr_float4_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_globals(device, scene); - - update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes); - - if (progress.get_cancel()) - return; - - /* copy to device */ - progress.set_status("Updating Mesh", "Copying Attributes to device"); - - dscene->attributes_float.copy_to_device_if_modified(); - dscene->attributes_float2.copy_to_device_if_modified(); - dscene->attributes_float3.copy_to_device_if_modified(); - dscene->attributes_float4.copy_to_device_if_modified(); - dscene->attributes_uchar4.copy_to_device_if_modified(); - - if (progress.get_cancel()) - return; - - /* After mesh attributes and patch tables have been copied to device memory, - * we need to update offsets in the objects. */ - scene->object_manager->device_update_geom_offsets(device, dscene, scene); } void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout) @@ -1040,375 +344,6 @@ void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout) } } -void GeometryManager::device_update_mesh(Device *, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - /* Count. */ - size_t vert_size = 0; - size_t tri_size = 0; - - size_t curve_key_size = 0; - size_t curve_size = 0; - size_t curve_segment_size = 0; - - size_t point_size = 0; - - size_t patch_size = 0; - - foreach (Geometry *geom, scene->geometry) { - if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { - Mesh *mesh = static_cast(geom); - - vert_size += mesh->verts.size(); - tri_size += mesh->num_triangles(); - - 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 */ - if (mesh->patch_table) { - mesh->patch_table_offset = patch_size; - patch_size += mesh->patch_table->total_size(); - } - } - } - else if (geom->is_hair()) { - Hair *hair = static_cast(geom); - - curve_key_size += hair->get_curve_keys().size(); - curve_size += hair->num_curves(); - curve_segment_size += hair->num_segments(); - } - else if (geom->is_pointcloud()) { - PointCloud *pointcloud = static_cast(geom); - point_size += pointcloud->num_points(); - } - } - - /* Fill in all the arrays. */ - if (tri_size != 0) { - /* normals */ - progress.set_status("Updating Mesh", "Computing normals"); - - packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size); - uint *tri_shader = dscene->tri_shader.alloc(tri_size); - packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size); - packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size); - uint *tri_patch = dscene->tri_patch.alloc(tri_size); - float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); - - const bool copy_all_data = dscene->tri_shader.need_realloc() || - dscene->tri_vindex.need_realloc() || - dscene->tri_vnormal.need_realloc() || - dscene->tri_patch.need_realloc() || - dscene->tri_patch_uv.need_realloc(); - - foreach (Geometry *geom, scene->geometry) { - if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { - Mesh *mesh = static_cast(geom); - - if (mesh->shader_is_modified() || mesh->smooth_is_modified() || - mesh->triangles_is_modified() || copy_all_data) { - mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); - } - - if (mesh->verts_is_modified() || copy_all_data) { - mesh->pack_normals(&vnormal[mesh->vert_offset]); - } - - if (mesh->verts_is_modified() || mesh->triangles_is_modified() || - mesh->vert_patch_uv_is_modified() || copy_all_data) { - mesh->pack_verts(&tri_verts[mesh->vert_offset], - &tri_vindex[mesh->prim_offset], - &tri_patch[mesh->prim_offset], - &tri_patch_uv[mesh->vert_offset]); - } - - if (progress.get_cancel()) - return; - } - } - - /* vertex coordinates */ - progress.set_status("Updating Mesh", "Copying Mesh to device"); - - dscene->tri_verts.copy_to_device_if_modified(); - dscene->tri_shader.copy_to_device_if_modified(); - dscene->tri_vnormal.copy_to_device_if_modified(); - dscene->tri_vindex.copy_to_device_if_modified(); - dscene->tri_patch.copy_to_device_if_modified(); - dscene->tri_patch_uv.copy_to_device_if_modified(); - } - - if (curve_segment_size != 0) { - progress.set_status("Updating Mesh", "Copying Curves to device"); - - float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); - KernelCurve *curves = dscene->curves.alloc(curve_size); - KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size); - - const bool copy_all_data = dscene->curve_keys.need_realloc() || - dscene->curves.need_realloc() || - dscene->curve_segments.need_realloc(); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_hair()) { - Hair *hair = static_cast(geom); - - bool curve_keys_co_modified = hair->curve_radius_is_modified() || - hair->curve_keys_is_modified(); - bool curve_data_modified = hair->curve_shader_is_modified() || - hair->curve_first_key_is_modified(); - - if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) { - continue; - } - - hair->pack_curves(scene, - &curve_keys[hair->curve_key_offset], - &curves[hair->prim_offset], - &curve_segments[hair->curve_segment_offset]); - if (progress.get_cancel()) - return; - } - } - - dscene->curve_keys.copy_to_device_if_modified(); - dscene->curves.copy_to_device_if_modified(); - dscene->curve_segments.copy_to_device_if_modified(); - } - - if (point_size != 0) { - progress.set_status("Updating Mesh", "Copying Point clouds to device"); - - float4 *points = dscene->points.alloc(point_size); - uint *points_shader = dscene->points_shader.alloc(point_size); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_pointcloud()) { - PointCloud *pointcloud = static_cast(geom); - pointcloud->pack( - scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]); - if (progress.get_cancel()) - return; - } - } - - dscene->points.copy_to_device(); - dscene->points_shader.copy_to_device(); - } - - if (patch_size != 0 && dscene->patches.need_realloc()) { - progress.set_status("Updating Mesh", "Copying Patches to device"); - - uint *patch_data = dscene->patches.alloc(patch_size); - - foreach (Geometry *geom, scene->geometry) { - if (geom->is_mesh()) { - Mesh *mesh = static_cast(geom); - mesh->pack_patches(&patch_data[mesh->patch_offset]); - - if (mesh->patch_table) { - mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], - mesh->patch_table_offset); - } - - if (progress.get_cancel()) - return; - } - } - - dscene->patches.copy_to_device(); - } -} - -void GeometryManager::device_update_bvh(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - /* bvh build */ - progress.set_status("Updating Scene BVH", "Building"); - - BVHParams bparams; - bparams.top_level = true; - bparams.bvh_layout = BVHParams::best_bvh_layout( - scene->params.bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); - bparams.use_spatial_split = scene->params.use_bvh_spatial_split; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - scene->params.use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; - bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; - bparams.num_motion_point_steps = scene->params.num_bvh_time_steps; - bparams.bvh_type = scene->params.bvh_type; - bparams.curve_subdivisions = scene->params.curve_subdivisions(); - - VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; - - const bool can_refit = scene->bvh != nullptr && - (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX || - bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL); - - BVH *bvh = scene->bvh; - if (!scene->bvh) { - bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device); - } - - device->build_bvh(bvh, progress, can_refit); - - if (progress.get_cancel()) { - return; - } - - const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2); - - PackedBVH pack; - if (has_bvh2_layout) { - pack = std::move(static_cast(bvh)->pack); - } - else { - pack.root_index = -1; - } - - /* copy to device */ - progress.set_status("Updating Scene BVH", "Copying BVH to device"); - - /* When using BVH2, we always have to copy/update the data as its layout is dependent on the - * BVH's leaf nodes which may be different when the objects or vertices move. */ - - if (pack.nodes.size()) { - dscene->bvh_nodes.steal_data(pack.nodes); - dscene->bvh_nodes.copy_to_device(); - } - if (pack.leaf_nodes.size()) { - dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); - dscene->bvh_leaf_nodes.copy_to_device(); - } - if (pack.object_node.size()) { - dscene->object_node.steal_data(pack.object_node); - dscene->object_node.copy_to_device(); - } - if (pack.prim_type.size()) { - dscene->prim_type.steal_data(pack.prim_type); - dscene->prim_type.copy_to_device(); - } - if (pack.prim_visibility.size()) { - dscene->prim_visibility.steal_data(pack.prim_visibility); - dscene->prim_visibility.copy_to_device(); - } - if (pack.prim_index.size()) { - dscene->prim_index.steal_data(pack.prim_index); - dscene->prim_index.copy_to_device(); - } - if (pack.prim_object.size()) { - dscene->prim_object.steal_data(pack.prim_object); - dscene->prim_object.copy_to_device(); - } - if (pack.prim_time.size()) { - dscene->prim_time.steal_data(pack.prim_time); - dscene->prim_time.copy_to_device(); - } - - dscene->data.bvh.root = pack.root_index; - dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); - dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions(); - /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */ - dscene->data.device_bvh = 0; -} - -/* Set of flags used to help determining what data has been modified or needs reallocation, so we - * can decide which device data to free or update. */ -enum { - DEVICE_CURVE_DATA_MODIFIED = (1 << 0), - DEVICE_MESH_DATA_MODIFIED = (1 << 1), - DEVICE_POINT_DATA_MODIFIED = (1 << 2), - - ATTR_FLOAT_MODIFIED = (1 << 3), - ATTR_FLOAT2_MODIFIED = (1 << 4), - ATTR_FLOAT3_MODIFIED = (1 << 5), - ATTR_FLOAT4_MODIFIED = (1 << 6), - ATTR_UCHAR4_MODIFIED = (1 << 7), - - CURVE_DATA_NEED_REALLOC = (1 << 8), - MESH_DATA_NEED_REALLOC = (1 << 9), - POINT_DATA_NEED_REALLOC = (1 << 10), - - ATTR_FLOAT_NEEDS_REALLOC = (1 << 11), - ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12), - ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13), - ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14), - - ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15), - - ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | - ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | - ATTR_UCHAR4_NEEDS_REALLOC), - DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), - DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), - DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), -}; - -static void update_device_flags_attribute(uint32_t &device_update_flags, - const AttributeSet &attributes) -{ - foreach (const Attribute &attr, attributes.attributes) { - if (!attr.modified) { - continue; - } - - AttrKernelDataType kernel_type = Attribute::kernel_type(attr); - - switch (kernel_type) { - case AttrKernelDataType::FLOAT: { - device_update_flags |= ATTR_FLOAT_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT2: { - device_update_flags |= ATTR_FLOAT2_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT3: { - device_update_flags |= ATTR_FLOAT3_MODIFIED; - break; - } - case AttrKernelDataType::FLOAT4: { - device_update_flags |= ATTR_FLOAT4_MODIFIED; - break; - } - case AttrKernelDataType::UCHAR4: { - device_update_flags |= ATTR_UCHAR4_MODIFIED; - break; - } - case AttrKernelDataType::NUM: { - break; - } - } - } -} - -static void update_attribute_realloc_flags(uint32_t &device_update_flags, - const AttributeSet &attributes) -{ - if (attributes.modified(AttrKernelDataType::FLOAT)) { - device_update_flags |= ATTR_FLOAT_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT2)) { - device_update_flags |= ATTR_FLOAT2_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT3)) { - device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::FLOAT4)) { - device_update_flags |= ATTR_FLOAT4_NEEDS_REALLOC; - } - if (attributes.modified(AttrKernelDataType::UCHAR4)) { - device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC; - } -} - void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress) { if (!need_update() && !need_flags_update) { diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h index 8a1bdc33a6f..335e0859965 100644 --- a/intern/cycles/scene/geometry.h +++ b/intern/cycles/scene/geometry.h @@ -30,6 +30,38 @@ class Shader; class Volume; struct PackedBVH; +/* Set of flags used to help determining what data has been modified or needs reallocation, so we + * can decide which device data to free or update. */ +enum { + DEVICE_CURVE_DATA_MODIFIED = (1 << 0), + DEVICE_MESH_DATA_MODIFIED = (1 << 1), + DEVICE_POINT_DATA_MODIFIED = (1 << 2), + + ATTR_FLOAT_MODIFIED = (1 << 3), + ATTR_FLOAT2_MODIFIED = (1 << 4), + ATTR_FLOAT3_MODIFIED = (1 << 5), + ATTR_FLOAT4_MODIFIED = (1 << 6), + ATTR_UCHAR4_MODIFIED = (1 << 7), + + CURVE_DATA_NEED_REALLOC = (1 << 8), + MESH_DATA_NEED_REALLOC = (1 << 9), + POINT_DATA_NEED_REALLOC = (1 << 10), + + ATTR_FLOAT_NEEDS_REALLOC = (1 << 11), + ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12), + ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13), + ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14), + + ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15), + + ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | + ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | + ATTR_UCHAR4_NEEDS_REALLOC), + DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), + DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), + DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), +}; + /* Geometry * * Base class for geometric types like Mesh and Hair. */ diff --git a/intern/cycles/scene/geometry_attributes.cpp b/intern/cycles/scene/geometry_attributes.cpp new file mode 100644 index 00000000000..c8f2d4a6e28 --- /dev/null +++ b/intern/cycles/scene/geometry_attributes.cpp @@ -0,0 +1,722 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#include "kernel/osl/globals.h" + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +bool Geometry::need_attribute(Scene *scene, AttributeStandard std) +{ + if (std == ATTR_STD_NONE) + return false; + + if (scene->need_global_attribute(std)) + return true; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast(node); + if (shader->attributes.find(std)) + return true; + } + + return false; +} + +bool Geometry::need_attribute(Scene * /*scene*/, ustring name) +{ + if (name == ustring()) + return false; + + foreach (Node *node, used_shaders) { + Shader *shader = static_cast(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(node); + result.add(shader->attributes); + } + + return result; +} + +bool Geometry::has_voxel_attributes() const +{ + foreach (const Attribute &attr, attributes.attributes) { + if (attr.element == ATTR_ELEMENT_VOXEL) { + return true; + } + } + + return false; +} + +/* Generate a normal attribute map entry from an attribute descriptor. */ +static void emit_attribute_map_entry(AttributeMap *attr_map, + size_t index, + uint64_t id, + TypeDesc type, + const AttributeDescriptor &desc) +{ + attr_map[index].id = id; + attr_map[index].element = desc.element; + attr_map[index].offset = as_uint(desc.offset); + + if (type == TypeDesc::TypeFloat) + attr_map[index].type = NODE_ATTR_FLOAT; + else if (type == TypeDesc::TypeMatrix) + attr_map[index].type = NODE_ATTR_MATRIX; + else if (type == TypeFloat2) + attr_map[index].type = NODE_ATTR_FLOAT2; + else if (type == TypeFloat4) + attr_map[index].type = NODE_ATTR_FLOAT4; + else if (type == TypeRGBA) + attr_map[index].type = NODE_ATTR_RGBA; + else + attr_map[index].type = NODE_ATTR_FLOAT3; + + attr_map[index].flags = desc.flags; +} + +/* 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(AttributeMap *attr_map, + size_t index, + bool chain, + uint chain_link) +{ + for (int j = 0; j < ATTR_PRIM_TYPES; j++) { + attr_map[index + j].id = ATTR_STD_NONE; + attr_map[index + j].element = chain; /* link is valid flag */ + attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */ + attr_map[index + j].type = 0; + attr_map[index + j].flags = 0; + } +} + +/* Generate all necessary attribute map entries from the attribute request. */ +static void emit_attribute_mapping( + AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom) +{ + emit_attribute_map_entry(attr_map, index, id, req.type, req.desc); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(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 &geom_attributes, + vector &object_attributes) +{ + /* for SVM, the attributes_map table is used to lookup the offset of an + * attribute, based on a unique shader attribute id. */ + + /* compute array stride */ + size_t attr_map_size = 0; + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + geom->attr_map_offset = attr_map_size; + +#ifdef WITH_OSL + size_t attr_count = 0; + foreach (AttributeRequest &req, geom_attributes[i].requests) { + if (req.std != ATTR_STD_NONE && + scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std) + attr_count += 2; + else + attr_count += 1; + } +#else + const size_t attr_count = geom_attributes[i].size(); +#endif + + attr_map_size += (attr_count + 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; + + if (!dscene->attributes_map.need_realloc()) { + return; + } + + /* create attribute map */ + AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size); + memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map)); + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + + /* set geometry attributes */ + size_t index = geom->attr_map_offset; + + foreach (AttributeRequest &req, attributes.requests) { + uint64_t 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_mapping(attr_map, index, id, req, geom); + index += ATTR_PRIM_TYPES; + +#ifdef WITH_OSL + /* Some standard attributes are explicitly referenced via their standard ID, so add those + * again in case they were added under a different attribute ID. */ + if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) { + emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom); + index += ATTR_PRIM_TYPES; + } +#endif + } + + emit_attribute_map_terminator(attr_map, index, false, 0); + } + + for (size_t i = 0; i < scene->objects.size(); i++) { + Object *object = scene->objects[i]; + AttributeRequestSet &attributes = object_attributes[i]; + + /* set object attributes */ + if (attributes.size() > 0) { + size_t index = object->attr_map_offset; + + foreach (AttributeRequest &req, attributes.requests) { + uint64_t 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_mapping(attr_map, index, id, req, object->geometry); + index += ATTR_PRIM_TYPES; + } + + emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset); + } + } + + /* copy to device */ + dscene->attributes_map.copy_to_device(); +} + +void GeometryManager::update_attribute_element_offset(Geometry *geom, + device_vector &attr_float, + size_t &attr_float_offset, + device_vector &attr_float2, + size_t &attr_float2_offset, + device_vector &attr_float3, + size_t &attr_float3_offset, + device_vector &attr_float4, + size_t &attr_float4_offset, + device_vector &attr_uchar4, + size_t &attr_uchar4_offset, + Attribute *mattr, + AttributePrimitive prim, + TypeDesc &type, + AttributeDescriptor &desc) +{ + if (mattr) { + /* store element and type */ + desc.element = mattr->element; + desc.flags = mattr->flags; + type = mattr->type; + + /* store attribute data in arrays */ + size_t size = mattr->element_size(geom, prim); + + AttributeElement &element = desc.element; + int &offset = desc.offset; + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* store slot in offset value */ + ImageHandle &handle = mattr->data_voxel(); + offset = handle.svm_slot(); + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + uchar4 *data = mattr->data_uchar4(); + offset = attr_uchar4_offset; + + assert(attr_uchar4.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_uchar4[offset + k] = data[k]; + } + attr_uchar4.tag_modified(); + } + attr_uchar4_offset += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + float *data = mattr->data_float(); + offset = attr_float_offset; + + assert(attr_float.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float[offset + k] = data[k]; + } + attr_float.tag_modified(); + } + attr_float_offset += size; + } + else if (mattr->type == TypeFloat2) { + float2 *data = mattr->data_float2(); + offset = attr_float2_offset; + + assert(attr_float2.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float2[offset + k] = data[k]; + } + attr_float2.tag_modified(); + } + attr_float2_offset += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + Transform *tfm = mattr->data_transform(); + offset = attr_float4_offset; + + assert(attr_float4.size() >= offset + size * 3); + if (mattr->modified) { + for (size_t k = 0; k < size * 3; k++) { + attr_float4[offset + k] = (&tfm->x)[k]; + } + attr_float4.tag_modified(); + } + attr_float4_offset += size * 3; + } + else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { + float4 *data = mattr->data_float4(); + offset = attr_float4_offset; + + assert(attr_float4.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float4[offset + k] = data[k]; + } + attr_float4.tag_modified(); + } + attr_float4_offset += size; + } + else { + float3 *data = mattr->data_float3(); + offset = attr_float3_offset; + + assert(attr_float3.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float3[offset + k] = data[k]; + } + attr_float3.tag_modified(); + } + attr_float3_offset += size; + } + + /* mesh vertex/curve index is global, not per object, so we sneak + * a correction for that in here */ + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && + desc.flags & ATTR_SUBDIVIDED) { + /* Indices for subdivided attributes are retrieved + * from patch table so no need for correction here. */ + } + else if (element == ATTR_ELEMENT_VERTEX) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_FACE) { + if (prim == ATTR_PRIM_GEOMETRY) + offset -= mesh->prim_offset; + else + offset -= mesh->face_offset; + } + else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { + if (prim == ATTR_PRIM_GEOMETRY) + offset -= 3 * mesh->prim_offset; + else + offset -= mesh->corner_offset; + } + } + else if (geom->is_hair()) { + Hair *hair = static_cast(geom); + if (element == ATTR_ELEMENT_CURVE) + offset -= hair->prim_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY) + offset -= hair->curve_key_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) + offset -= hair->curve_key_offset; + } + else if (geom->is_pointcloud()) { + if (element == ATTR_ELEMENT_VERTEX) + offset -= geom->prim_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= geom->prim_offset; + } + } + else { + /* attribute not found */ + desc.element = ATTR_ELEMENT_NONE; + desc.offset = 0; + } +} + +static void update_attribute_element_size(Geometry *geom, + Attribute *mattr, + AttributePrimitive prim, + size_t *attr_float_size, + size_t *attr_float2_size, + size_t *attr_float3_size, + size_t *attr_float4_size, + size_t *attr_uchar4_size) +{ + if (mattr) { + size_t size = mattr->element_size(geom, prim); + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* pass */ + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + *attr_uchar4_size += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + *attr_float_size += size; + } + else if (mattr->type == TypeFloat2) { + *attr_float2_size += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + *attr_float4_size += size * 4; + } + else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { + *attr_float4_size += size; + } + else { + *attr_float3_size += size; + } + } +} + +void GeometryManager::device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + progress.set_status("Updating Mesh", "Computing attributes"); + + /* gather per mesh requested attributes. as meshes may have multiple + * shaders assigned, this merges the requested attributes that have + * been set per shader by the shader manager */ + vector geom_attributes(scene->geometry.size()); + + 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 (Node *node, geom->get_used_shaders()) { + Shader *shader = static_cast(node); + geom_attributes[i].add(shader->attributes); + } + + if (geom->is_hair() && static_cast(geom)->need_shadow_transparency()) { + geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY); + } + } + + /* convert object attributes to use the same data structures as geometry ones */ + vector object_attributes(scene->objects.size()); + vector 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 */ + + /* Pre-allocate attributes to avoid arrays re-allocation which would + * take 2x of overall attribute memory usage. + */ + size_t attr_float_size = 0; + size_t attr_float2_size = 0; + size_t attr_float3_size = 0; + size_t attr_float4_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]; + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = geom->attributes.find(req); + + update_attribute_element_size(geom, + attr, + ATTR_PRIM_GEOMETRY, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_float4_size, + &attr_uchar4_size); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + Attribute *subd_attr = mesh->subd_attributes.find(req); + + update_attribute_element_size(mesh, + subd_attr, + ATTR_PRIM_SUBD, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_float4_size, + &attr_uchar4_size); + } + } + } + + 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_float4_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); + dscene->attributes_float4.alloc(attr_float4_size); + dscene->attributes_uchar4.alloc(attr_uchar4_size); + + /* The order of those flags needs to match that of AttrKernelDataType. */ + const bool attributes_need_realloc[AttrKernelDataType::NUM] = { + dscene->attributes_float.need_realloc(), + dscene->attributes_float2.need_realloc(), + dscene->attributes_float3.need_realloc(), + dscene->attributes_float4.need_realloc(), + dscene->attributes_uchar4.need_realloc(), + }; + + size_t attr_float_offset = 0; + size_t attr_float2_offset = 0; + size_t attr_float3_offset = 0; + size_t attr_float4_offset = 0; + size_t attr_uchar4_offset = 0; + + /* Fill in attributes. */ + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + + /* todo: we now store std and name attributes from requests even if + * they actually refer to the same mesh attributes, optimize */ + foreach (AttributeRequest &req, attributes.requests) { + Attribute *attr = geom->attributes.find(req); + + if (attr) { + /* force a copy if we need to reallocate all the data */ + attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; + } + + update_attribute_element_offset(geom, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + attr, + ATTR_PRIM_GEOMETRY, + req.type, + req.desc); + + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + Attribute *subd_attr = mesh->subd_attributes.find(req); + + if (subd_attr) { + /* force a copy if we need to reallocate all the data */ + subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)]; + } + + update_attribute_element_offset(mesh, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + subd_attr, + ATTR_PRIM_SUBD, + req.subd_type, + req.subd_desc); + } + + if (progress.get_cancel()) + return; + } + } + + 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); + + if (attr) { + attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)]; + } + + 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_float4, + attr_float4_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_globals(device, scene); + + update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes); + + if (progress.get_cancel()) + return; + + /* copy to device */ + progress.set_status("Updating Mesh", "Copying Attributes to device"); + + dscene->attributes_float.copy_to_device_if_modified(); + dscene->attributes_float2.copy_to_device_if_modified(); + dscene->attributes_float3.copy_to_device_if_modified(); + dscene->attributes_float4.copy_to_device_if_modified(); + dscene->attributes_uchar4.copy_to_device_if_modified(); + + if (progress.get_cancel()) + return; + + /* After mesh attributes and patch tables have been copied to device memory, + * we need to update offsets in the objects. */ + scene->object_manager->device_update_geom_offsets(device, dscene, scene); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/geometry_bvh.cpp b/intern/cycles/scene/geometry_bvh.cpp new file mode 100644 index 00000000000..9785d1a867a --- /dev/null +++ b/intern/cycles/scene/geometry_bvh.cpp @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#include "kernel/osl/globals.h" + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +void Geometry::compute_bvh(Device *device, + DeviceScene *dscene, + SceneParams *params, + Progress *progress, + size_t n, + size_t total) +{ + if (progress->get_cancel()) + return; + + compute_bounds(); + + const BVHLayout bvh_layout = BVHParams::best_bvh_layout( + params->bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); + if (need_build_bvh(bvh_layout)) { + string msg = "Updating Geometry BVH "; + if (name.empty()) + msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); + else + msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); + + Object object; + + /* Ensure all visibility bits are set at the geometry level BVH. In + * the object level BVH is where actual visibility is tested. */ + object.set_is_shadow_catcher(true); + object.set_visibility(~0); + + object.set_geometry(this); + + vector geometry; + geometry.push_back(this); + vector objects; + objects.push_back(&object); + + if (bvh && !need_update_rebuild) { + progress->set_status(msg, "Refitting BVH"); + + bvh->replace_geometry(geometry, objects); + + device->build_bvh(bvh, *progress, true); + } + else { + progress->set_status(msg, "Building BVH"); + + BVHParams bparams; + bparams.use_spatial_split = params->use_bvh_spatial_split; + bparams.use_compact_structure = params->use_bvh_compact_structure; + bparams.bvh_layout = bvh_layout; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = params->num_bvh_time_steps; + bparams.num_motion_curve_steps = params->num_bvh_time_steps; + bparams.num_motion_point_steps = params->num_bvh_time_steps; + bparams.bvh_type = params->bvh_type; + bparams.curve_subdivisions = params->curve_subdivisions(); + + delete bvh; + bvh = BVH::create(bparams, geometry, objects, device); + MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false); + } + } + + need_update_rebuild = false; + need_update_bvh_for_offset = false; +} + +void GeometryManager::device_update_bvh(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + /* bvh build */ + progress.set_status("Updating Scene BVH", "Building"); + + BVHParams bparams; + bparams.top_level = true; + bparams.bvh_layout = BVHParams::best_bvh_layout( + scene->params.bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features)); + bparams.use_spatial_split = scene->params.use_bvh_spatial_split; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_point_steps = scene->params.num_bvh_time_steps; + bparams.bvh_type = scene->params.bvh_type; + bparams.curve_subdivisions = scene->params.curve_subdivisions(); + + VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; + + const bool can_refit = scene->bvh != nullptr && + (bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX || + bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL); + + BVH *bvh = scene->bvh; + if (!scene->bvh) { + bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device); + } + + device->build_bvh(bvh, progress, can_refit); + + if (progress.get_cancel()) { + return; + } + + const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2); + + PackedBVH pack; + if (has_bvh2_layout) { + pack = std::move(static_cast(bvh)->pack); + } + else { + pack.root_index = -1; + } + + /* copy to device */ + progress.set_status("Updating Scene BVH", "Copying BVH to device"); + + /* When using BVH2, we always have to copy/update the data as its layout is dependent on the + * BVH's leaf nodes which may be different when the objects or vertices move. */ + + if (pack.nodes.size()) { + dscene->bvh_nodes.steal_data(pack.nodes); + dscene->bvh_nodes.copy_to_device(); + } + if (pack.leaf_nodes.size()) { + dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); + dscene->bvh_leaf_nodes.copy_to_device(); + } + if (pack.object_node.size()) { + dscene->object_node.steal_data(pack.object_node); + dscene->object_node.copy_to_device(); + } + if (pack.prim_type.size()) { + dscene->prim_type.steal_data(pack.prim_type); + dscene->prim_type.copy_to_device(); + } + if (pack.prim_visibility.size()) { + dscene->prim_visibility.steal_data(pack.prim_visibility); + dscene->prim_visibility.copy_to_device(); + } + if (pack.prim_index.size()) { + dscene->prim_index.steal_data(pack.prim_index); + dscene->prim_index.copy_to_device(); + } + if (pack.prim_object.size()) { + dscene->prim_object.steal_data(pack.prim_object); + dscene->prim_object.copy_to_device(); + } + if (pack.prim_time.size()) { + dscene->prim_time.steal_data(pack.prim_time); + dscene->prim_time.copy_to_device(); + } + + dscene->data.bvh.root = pack.root_index; + dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); + dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions(); + /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */ + dscene->data.device_bvh = 0; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/geometry_mesh.cpp b/intern/cycles/scene/geometry_mesh.cpp new file mode 100644 index 00000000000..954a79f9de7 --- /dev/null +++ b/intern/cycles/scene/geometry_mesh.cpp @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "bvh/bvh.h" +#include "bvh/bvh2.h" + +#include "device/device.h" + +#include "scene/attribute.h" +#include "scene/camera.h" +#include "scene/geometry.h" +#include "scene/hair.h" +#include "scene/light.h" +#include "scene/mesh.h" +#include "scene/object.h" +#include "scene/osl.h" +#include "scene/pointcloud.h" +#include "scene/scene.h" +#include "scene/shader.h" +#include "scene/shader_nodes.h" +#include "scene/stats.h" +#include "scene/volume.h" + +#include "subd/patch_table.h" +#include "subd/split.h" + +#ifdef WITH_OSL +# include "kernel/osl/globals.h" +#endif + +#include "util/foreach.h" +#include "util/log.h" +#include "util/progress.h" +#include "util/task.h" + +CCL_NAMESPACE_BEGIN + +void GeometryManager::device_update_mesh(Device *, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + /* Count. */ + size_t vert_size = 0; + size_t tri_size = 0; + + size_t curve_key_size = 0; + size_t curve_size = 0; + size_t curve_segment_size = 0; + + size_t point_size = 0; + + size_t patch_size = 0; + + foreach (Geometry *geom, scene->geometry) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { + Mesh *mesh = static_cast(geom); + + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + + 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 */ + if (mesh->patch_table) { + mesh->patch_table_offset = patch_size; + patch_size += mesh->patch_table->total_size(); + } + } + } + else if (geom->is_hair()) { + Hair *hair = static_cast(geom); + + curve_key_size += hair->get_curve_keys().size(); + curve_size += hair->num_curves(); + curve_segment_size += hair->num_segments(); + } + else if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast(geom); + point_size += pointcloud->num_points(); + } + } + + /* Fill in all the arrays. */ + if (tri_size != 0) { + /* normals */ + progress.set_status("Updating Mesh", "Computing normals"); + + packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size); + uint *tri_shader = dscene->tri_shader.alloc(tri_size); + packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size); + packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size); + uint *tri_patch = dscene->tri_patch.alloc(tri_size); + float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); + + const bool copy_all_data = dscene->tri_shader.need_realloc() || + dscene->tri_vindex.need_realloc() || + dscene->tri_vnormal.need_realloc() || + dscene->tri_patch.need_realloc() || + dscene->tri_patch_uv.need_realloc(); + + foreach (Geometry *geom, scene->geometry) { + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { + Mesh *mesh = static_cast(geom); + + if (mesh->shader_is_modified() || mesh->smooth_is_modified() || + mesh->triangles_is_modified() || copy_all_data) { + mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); + } + + if (mesh->verts_is_modified() || copy_all_data) { + mesh->pack_normals(&vnormal[mesh->vert_offset]); + } + + if (mesh->verts_is_modified() || mesh->triangles_is_modified() || + mesh->vert_patch_uv_is_modified() || copy_all_data) { + mesh->pack_verts(&tri_verts[mesh->vert_offset], + &tri_vindex[mesh->prim_offset], + &tri_patch[mesh->prim_offset], + &tri_patch_uv[mesh->vert_offset]); + } + + if (progress.get_cancel()) + return; + } + } + + /* vertex coordinates */ + progress.set_status("Updating Mesh", "Copying Mesh to device"); + + dscene->tri_verts.copy_to_device_if_modified(); + dscene->tri_shader.copy_to_device_if_modified(); + dscene->tri_vnormal.copy_to_device_if_modified(); + dscene->tri_vindex.copy_to_device_if_modified(); + dscene->tri_patch.copy_to_device_if_modified(); + dscene->tri_patch_uv.copy_to_device_if_modified(); + } + + if (curve_segment_size != 0) { + progress.set_status("Updating Mesh", "Copying Curves to device"); + + float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); + KernelCurve *curves = dscene->curves.alloc(curve_size); + KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size); + + const bool copy_all_data = dscene->curve_keys.need_realloc() || + dscene->curves.need_realloc() || + dscene->curve_segments.need_realloc(); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_hair()) { + Hair *hair = static_cast(geom); + + bool curve_keys_co_modified = hair->curve_radius_is_modified() || + hair->curve_keys_is_modified(); + bool curve_data_modified = hair->curve_shader_is_modified() || + hair->curve_first_key_is_modified(); + + if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) { + continue; + } + + hair->pack_curves(scene, + &curve_keys[hair->curve_key_offset], + &curves[hair->prim_offset], + &curve_segments[hair->curve_segment_offset]); + if (progress.get_cancel()) + return; + } + } + + dscene->curve_keys.copy_to_device_if_modified(); + dscene->curves.copy_to_device_if_modified(); + dscene->curve_segments.copy_to_device_if_modified(); + } + + if (point_size != 0) { + progress.set_status("Updating Mesh", "Copying Point clouds to device"); + + float4 *points = dscene->points.alloc(point_size); + uint *points_shader = dscene->points_shader.alloc(point_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_pointcloud()) { + PointCloud *pointcloud = static_cast(geom); + pointcloud->pack( + scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]); + if (progress.get_cancel()) + return; + } + } + + dscene->points.copy_to_device(); + dscene->points_shader.copy_to_device(); + } + + if (patch_size != 0 && dscene->patches.need_realloc()) { + progress.set_status("Updating Mesh", "Copying Patches to device"); + + uint *patch_data = dscene->patches.alloc(patch_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->is_mesh()) { + Mesh *mesh = static_cast(geom); + mesh->pack_patches(&patch_data[mesh->patch_offset]); + + if (mesh->patch_table) { + mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], + mesh->patch_table_offset); + } + + if (progress.get_cancel()) + return; + } + } + + dscene->patches.copy_to_device(); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp index ee94e2bd724..2b68d1bd9a6 100644 --- a/intern/cycles/scene/scene.cpp +++ b/intern/cycles/scene/scene.cpp @@ -24,6 +24,7 @@ #include "scene/svm.h" #include "scene/tables.h" #include "scene/volume.h" +#include "scene/devicescene.h" #include "session/session.h" #include "util/foreach.h" @@ -33,59 +34,7 @@ CCL_NAMESPACE_BEGIN -DeviceScene::DeviceScene(Device *device) - : bvh_nodes(device, "bvh_nodes", MEM_GLOBAL), - bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL), - object_node(device, "object_node", MEM_GLOBAL), - prim_type(device, "prim_type", MEM_GLOBAL), - prim_visibility(device, "prim_visibility", MEM_GLOBAL), - prim_index(device, "prim_index", MEM_GLOBAL), - prim_object(device, "prim_object", MEM_GLOBAL), - prim_time(device, "prim_time", MEM_GLOBAL), - tri_verts(device, "tri_verts", MEM_GLOBAL), - tri_shader(device, "tri_shader", MEM_GLOBAL), - tri_vnormal(device, "tri_vnormal", MEM_GLOBAL), - tri_vindex(device, "tri_vindex", MEM_GLOBAL), - tri_patch(device, "tri_patch", MEM_GLOBAL), - tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL), - curves(device, "curves", MEM_GLOBAL), - curve_keys(device, "curve_keys", MEM_GLOBAL), - curve_segments(device, "curve_segments", MEM_GLOBAL), - patches(device, "patches", MEM_GLOBAL), - points(device, "points", MEM_GLOBAL), - points_shader(device, "points_shader", MEM_GLOBAL), - objects(device, "objects", MEM_GLOBAL), - object_motion_pass(device, "object_motion_pass", MEM_GLOBAL), - object_motion(device, "object_motion", MEM_GLOBAL), - object_flag(device, "object_flag", MEM_GLOBAL), - object_volume_step(device, "object_volume_step", MEM_GLOBAL), - object_prim_offset(device, "object_prim_offset", MEM_GLOBAL), - camera_motion(device, "camera_motion", MEM_GLOBAL), - attributes_map(device, "attributes_map", MEM_GLOBAL), - attributes_float(device, "attributes_float", MEM_GLOBAL), - attributes_float2(device, "attributes_float2", MEM_GLOBAL), - attributes_float3(device, "attributes_float3", MEM_GLOBAL), - attributes_float4(device, "attributes_float4", MEM_GLOBAL), - attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL), - light_distribution(device, "light_distribution", MEM_GLOBAL), - lights(device, "lights", MEM_GLOBAL), - light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL), - light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL), - light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL), - light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL), - light_to_tree(device, "light_to_tree", MEM_GLOBAL), - object_to_tree(device, "object_to_tree", MEM_GLOBAL), - object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL), - triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL), - particles(device, "particles", MEM_GLOBAL), - svm_nodes(device, "svm_nodes", MEM_GLOBAL), - shaders(device, "shaders", MEM_GLOBAL), - lookup_table(device, "lookup_table", MEM_GLOBAL), - sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL), - ies_lights(device, "ies", MEM_GLOBAL) -{ - memset((void *)&data, 0, sizeof(data)); -} + Scene::Scene(const SceneParams ¶ms_, Device *device) : name("Scene"), diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h index 8a522d88ac1..742d4db79f3 100644 --- a/intern/cycles/scene/scene.h +++ b/intern/cycles/scene/scene.h @@ -6,20 +6,16 @@ #include "bvh/params.h" +#include "scene/devicescene.h" #include "scene/film.h" #include "scene/image.h" #include "scene/shader.h" -#include "device/device.h" -#include "device/memory.h" - #include "util/param.h" #include "util/string.h" #include "util/system.h" #include "util/texture.h" #include "util/thread.h" -#include "util/types.h" -#include "util/vector.h" CCL_NAMESPACE_BEGIN @@ -54,92 +50,6 @@ class RenderStats; class SceneUpdateStats; class Volume; -/* Scene Device Data */ - -class DeviceScene { - public: - /* BVH */ - device_vector bvh_nodes; - device_vector bvh_leaf_nodes; - device_vector object_node; - device_vector prim_type; - device_vector prim_visibility; - device_vector prim_index; - device_vector prim_object; - device_vector prim_time; - - /* mesh */ - device_vector tri_verts; - device_vector tri_shader; - device_vector tri_vnormal; - device_vector tri_vindex; - device_vector tri_patch; - device_vector tri_patch_uv; - - device_vector curves; - device_vector curve_keys; - device_vector curve_segments; - - device_vector patches; - - /* point-cloud */ - device_vector points; - device_vector points_shader; - - /* objects */ - device_vector objects; - device_vector object_motion_pass; - device_vector object_motion; - device_vector object_flag; - device_vector object_volume_step; - device_vector object_prim_offset; - - /* cameras */ - device_vector camera_motion; - - /* attributes */ - device_vector attributes_map; - device_vector attributes_float; - device_vector attributes_float2; - device_vector attributes_float3; - device_vector attributes_float4; - device_vector attributes_uchar4; - - /* lights */ - device_vector light_distribution; - device_vector lights; - device_vector light_background_marginal_cdf; - device_vector light_background_conditional_cdf; - - /* light tree */ - device_vector light_tree_nodes; - device_vector light_tree_emitters; - device_vector light_to_tree; - device_vector object_to_tree; - device_vector object_lookup_offset; - device_vector triangle_to_tree; - - /* particles */ - device_vector particles; - - /* shaders */ - device_vector svm_nodes; - device_vector shaders; - - /* lookup tables */ - device_vector lookup_table; - - /* integrator */ - device_vector sample_pattern_lut; - - /* IES lights */ - device_vector ies_lights; - - KernelData data; - - DeviceScene(Device *device); -}; - /* Scene Parameters */ class SceneParams {