From aef0e72e5acccf5f86cabe17dc49d7af473901e9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 7 Apr 2023 15:25:05 -0400 Subject: [PATCH] Cycles: Optimize Blender point cloud attribute extraction Similar to 8d0920ec6dcd3fc7fc6b. In a test case with 8 million points and 3 attributes, I observed around a 9x performance improvement, from 1.8s to 0.2s to copy the data from Blender to Cycles. For some attribute types, using implicit sharing could remove the need to copy entirely, but removing the overhead from the RNA API makes sense anyway. --- intern/cycles/blender/pointcloud.cpp | 128 +++++++++++++++------------ 1 file changed, 69 insertions(+), 59 deletions(-) diff --git a/intern/cycles/blender/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp index cba0c7d23a0..920bcd01fae 100644 --- a/intern/cycles/blender/pointcloud.cpp +++ b/intern/cycles/blender/pointcloud.cpp @@ -15,17 +15,6 @@ CCL_NAMESPACE_BEGIN -template -static void fill_generic_attribute(BL::PointCloud &b_pointcloud, - TypeInCycles *data, - const GetValueAtIndex &get_value_at_index) -{ - const int num_points = b_pointcloud.points.length(); - for (int i = 0; i < num_points; i++) { - data[i] = get_value_at_index(i); - } -} - static void attr_create_motion(PointCloud *pointcloud, BL::Attribute &b_attribute, const float motion_scale) @@ -63,6 +52,11 @@ static void copy_attributes(PointCloud *pointcloud, const bool need_motion, const float motion_scale) { + const int num_points = b_pointcloud.points.length(); + if (num_points == 0) { + return; + } + AttributeSet &attributes = pointcloud->attributes; static const ustring u_velocity("velocity"); for (BL::Attribute &b_attribute : b_pointcloud.attributes) { @@ -81,56 +75,60 @@ static void copy_attributes(PointCloud *pointcloud, switch (b_data_type) { case BL::Attribute::data_type_FLOAT: { BL::FloatAttribute b_float_attribute{b_attribute}; + const float *src = static_cast(b_float_attribute.data[0].ptr.data); Attribute *attr = attributes.add(name, TypeFloat, element); float *data = attr->data_float(); - fill_generic_attribute( - b_pointcloud, data, [&](int i) { return b_float_attribute.data[i].value(); }); + std::copy(src, src + num_points, data); break; } case BL::Attribute::data_type_BOOLEAN: { BL::BoolAttribute b_bool_attribute{b_attribute}; + const bool *src = static_cast(b_bool_attribute.data[0].ptr.data); Attribute *attr = attributes.add(name, TypeFloat, element); float *data = attr->data_float(); - fill_generic_attribute( - b_pointcloud, data, [&](int i) { return (float)b_bool_attribute.data[i].value(); }); + for (int i = 0; i < num_points; i++) { + data[i] = float(src[i]); + } break; } case BL::Attribute::data_type_INT: { BL::IntAttribute b_int_attribute{b_attribute}; + const int *src = static_cast(b_int_attribute.data[0].ptr.data); Attribute *attr = attributes.add(name, TypeFloat, element); float *data = attr->data_float(); - fill_generic_attribute( - b_pointcloud, data, [&](int i) { return (float)b_int_attribute.data[i].value(); }); + for (int i = 0; i < num_points; i++) { + data[i] = float(src[i]); + } break; } case BL::Attribute::data_type_FLOAT_VECTOR: { BL::FloatVectorAttribute b_vector_attribute{b_attribute}; + const float(*src)[3] = static_cast(b_vector_attribute.data[0].ptr.data); Attribute *attr = attributes.add(name, TypeVector, element); float3 *data = attr->data_float3(); - fill_generic_attribute(b_pointcloud, data, [&](int i) { - BL::Array v = b_vector_attribute.data[i].vector(); - return make_float3(v[0], v[1], v[2]); - }); + for (int i = 0; i < num_points; i++) { + data[i] = make_float3(src[i][0], src[i][1], src[i][2]); + } break; } case BL::Attribute::data_type_FLOAT_COLOR: { BL::FloatColorAttribute b_color_attribute{b_attribute}; + const float(*src)[4] = static_cast(b_color_attribute.data[0].ptr.data); Attribute *attr = attributes.add(name, TypeRGBA, element); float4 *data = attr->data_float4(); - fill_generic_attribute(b_pointcloud, data, [&](int i) { - BL::Array v = b_color_attribute.data[i].color(); - return make_float4(v[0], v[1], v[2], v[3]); - }); + for (int i = 0; i < num_points; i++) { + data[i] = make_float4(src[i][0], src[i][1], src[i][2], src[i][3]); + } break; } case BL::Attribute::data_type_FLOAT2: { BL::Float2Attribute b_float2_attribute{b_attribute}; + const float(*src)[2] = static_cast(b_float2_attribute.data[0].ptr.data); Attribute *attr = attributes.add(name, TypeFloat2, element); float2 *data = attr->data_float2(); - fill_generic_attribute(b_pointcloud, data, [&](int i) { - BL::Array v = b_float2_attribute.data[i].vector(); - return make_float2(v[0], v[1]); - }); + for (int i = 0; i < num_points; i++) { + data[i] = make_float2(src[i][0], src[i][1]); + } break; } default: @@ -140,7 +138,7 @@ static void copy_attributes(PointCloud *pointcloud, } } -static std::optional find_radius_attribute(BL::PointCloud b_pointcloud) +static const float *find_radius_attribute(BL::PointCloud b_pointcloud) { for (BL::Attribute &b_attribute : b_pointcloud.attributes) { if (b_attribute.name() != "radius") { @@ -149,12 +147,16 @@ static std::optional find_radius_attribute(BL::PointCloud b_ if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) { continue; } - return BL::FloatAttribute{b_attribute}; + BL::FloatAttribute b_float_attribute{b_attribute}; + if (b_float_attribute.data.length() == 0) { + return nullptr; + } + return static_cast(b_float_attribute.data[0].ptr.data); } - return std::nullopt; + return nullptr; } -static BL::FloatVectorAttribute find_position_attribute(BL::PointCloud b_pointcloud) +static const float (*find_position_attribute(BL::PointCloud b_pointcloud))[3] { for (BL::Attribute &b_attribute : b_pointcloud.attributes) { if (b_attribute.name() != "position") { @@ -163,11 +165,15 @@ static BL::FloatVectorAttribute find_position_attribute(BL::PointCloud b_pointcl if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) { continue; } - return BL::FloatVectorAttribute{b_attribute}; + BL::FloatVectorAttribute b_float3_attribute{b_attribute}; + if (b_float3_attribute.data.length() == 0) { + return nullptr; + } + return static_cast(b_float3_attribute.data[0].ptr.data); } /* The position attribute must exist. */ assert(false); - return BL::FloatVectorAttribute{b_pointcloud.attributes[0]}; + return nullptr; } static void export_pointcloud(Scene *scene, @@ -176,34 +182,37 @@ static void export_pointcloud(Scene *scene, const bool need_motion, const float motion_scale) { - /* TODO: optimize so we can straight memcpy arrays from Blender? */ + const int num_points = b_pointcloud.points.length(); + pointcloud->resize(num_points); - /* Add requested attributes. */ - Attribute *attr_random = NULL; - if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) { - attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM); + const float(*b_attr_position)[3] = find_position_attribute(b_pointcloud); + float3 *points = pointcloud->get_points().data(); + std::cout << sizeof(*points) << '\n'; + + for (int i = 0; i < num_points; i++) { + points[i] = make_float3(b_attr_position[i][0], b_attr_position[i][1], b_attr_position[i][2]); } - /* Reserve memory. */ - const int num_points = b_pointcloud.points.length(); - pointcloud->reserve(num_points); + const float *b_attr_radius = find_radius_attribute(b_pointcloud); + float *radius = pointcloud->get_radius().data(); + if (b_attr_radius) { + std::copy(b_attr_radius, b_attr_radius + num_points, radius); + } + else { + std::fill(radius, radius + num_points, 0.01f); + } - BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud); - std::optional b_attr_radius = find_radius_attribute(b_pointcloud); + int *shader = pointcloud->get_shader().data(); + std::fill(shader, shader + num_points, 0); - /* Export points. */ - for (int i = 0; i < num_points; i++) { - const float3 co = get_float3(b_attr_position.data[i].vector()); - const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.01f; - pointcloud->add_point(co, radius); - - /* Random number per point. */ - if (attr_random != NULL) { - attr_random->add(hash_uint2_to_float(i, 0)); + if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) { + Attribute *attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM); + float *data = attr_random->data_float(); + for (int i = 0; i < num_points; i++) { + data[i] = hash_uint2_to_float(i, 0); } } - /* Export attributes */ copy_attributes(pointcloud, b_pointcloud, need_motion, motion_scale); } @@ -230,12 +239,13 @@ static void export_pointcloud_motion(PointCloud *pointcloud, const array &pointcloud_points = pointcloud->get_points(); const int b_points_num = b_pointcloud.points.length(); - BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud); - std::optional b_attr_radius = find_radius_attribute(b_pointcloud); + const float(*b_attr_position)[3] = find_position_attribute(b_pointcloud); + const float *b_attr_radius = find_radius_attribute(b_pointcloud); for (int i = 0; i < std::min(num_points, b_points_num); i++) { - const float3 P = get_float3(b_attr_position.data[i].vector()); - const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.01f; + const float3 P = make_float3( + b_attr_position[i][0], b_attr_position[i][1], b_attr_position[i][2]); + const float radius = b_attr_radius ? b_attr_radius[i] : 0.01f; mP[i] = make_float4(P.x, P.y, P.z, radius); have_motion = have_motion || (P != pointcloud_points[i]); }