From 0f97bbf9447e0787a36374f2e09be39d01e65a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D1=8F=20=5F?= Date: Fri, 15 Aug 2025 21:51:49 +0200 Subject: [PATCH] Refactor: Improve packaging of curve edit draw segments in memory Right after #143858 this refactor aim to fix issue with bezier curve handle segments location in index buffer object. Before there were a lot of unused segments. Now there is no any unused bit of memory. Pull Request: https://projects.blender.org/blender/blender/pulls/143966 --- .../draw/intern/draw_cache_impl_curves.cc | 102 +++++++++--------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index 25549c93be7..89fe4a78be7 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -474,19 +474,16 @@ static void create_lines_ibo_with_cyclic(const OffsetIndices points_by_curv } } -static void extract_curve_lines(const OffsetIndices points_by_curve, - const VArray &cyclic, - const IndexMask &selection, - const int cyclic_segment_offset, - MutableSpan lines) +static void create_segments_with_cyclic(const OffsetIndices points_by_curve, + const VArray &cyclic, + const IndexMask &selection, + MutableSpan lines) { selection.foreach_index(GrainSize(512), [&](const int curve) { const IndexRange points = points_by_curve[curve]; - MutableSpan curve_lines = lines.slice(points.start() + cyclic_segment_offset, - points.size() + 1); - for (const int i : IndexRange(points.size() - 1)) { - const int point = points[i]; - curve_lines[i] = uint2(point, point + 1); + MutableSpan curve_lines = lines.slice(points); + for (const int i : points.index_range().drop_back(1)) { + curve_lines[i] = uint2(points[i]) + uint2(0, 1); } if (cyclic[curve]) { curve_lines.last() = uint2(points.first(), points.last()); @@ -506,59 +503,58 @@ static void calc_edit_handles_ibo(const OffsetIndices points_by_curve, const VArray &cyclic, gpu::IndexBuf &ibo) { - const int curves_num = points_by_curve.size(); + /* All curve types have poly-line segments draw of original (non-evaluate) topology to connect + * control points. Bezier have exception -- instead there is left and right handle segments. Left + * bezier handle segments point to original and handle points and lie at index of curve segment. + * Right bezier handle segments point to original and handle points and lie in a sequence after + * all other segments. */ const int points_num = points_by_curve.total_size(); - const int non_bezier_points_num = points_num - bezier_offsets.total_size(); - const int non_bezier_curves_num = curves_num - bezier_curves.size(); - - int lines_num = 0; - /* Lines for all non-cyclic non-Bezier segments. */ - lines_num += non_bezier_points_num; - /* Lines for all potential non-Bezier cyclic segments. */ - lines_num += non_bezier_curves_num; - /* Lines for all Bezier handles. */ - lines_num += bezier_offsets.total_size() * 2; + const int extra_bezier_segments = bezier_offsets.total_size(); + /* TODO: Use linestrip if there is no bezier curves. */ GPUIndexBufBuilder builder; - GPU_indexbuf_init( - &builder, GPU_PRIM_LINES, lines_num, handles_and_points_num(points_num, bezier_offsets)); + GPU_indexbuf_init(&builder, + GPU_PRIM_LINES, + points_num + extra_bezier_segments, + handles_and_points_num(points_num, bezier_offsets)); MutableSpan lines = GPU_indexbuf_get_data(&builder).cast(); + BLI_assert(lines.size() == points_num + extra_bezier_segments); + MutableSpan curve_or_handle_segments = lines.take_front(points_num); - /* All bezier segments are allocated since they form a gaps between other curves but are unused. - */ - /* TODO: Lay left handles in space allocated for bezier segments and right handles right after - * all segments. */ - lines.fill(uint2(0)); +#ifdef NDEBUG + lines.fill(uint2(std::numeric_limits::min())); +#endif - int cyclic_segment_offset = 0; - extract_curve_lines(points_by_curve, cyclic, catmull_rom_curves, cyclic_segment_offset, lines); - cyclic_segment_offset += catmull_rom_curves.size(); + create_segments_with_cyclic( + points_by_curve, cyclic, catmull_rom_curves, curve_or_handle_segments); + create_segments_with_cyclic(points_by_curve, cyclic, poly_curves, curve_or_handle_segments); + create_segments_with_cyclic(points_by_curve, cyclic, nurbs_curves, curve_or_handle_segments); - extract_curve_lines(points_by_curve, cyclic, poly_curves, cyclic_segment_offset, lines); - cyclic_segment_offset += catmull_rom_curves.size(); + const IndexRange handles_left = handle_range_left(points_num, bezier_offsets); + const IndexRange handles_right = handle_range_right(points_num, bezier_offsets); - if (!bezier_curves.is_empty()) { - const IndexRange handles_left = handle_range_left(points_num, bezier_offsets); - const IndexRange handles_right = handle_range_right(points_num, bezier_offsets); + bezier_curves.foreach_index(GrainSize(512), [&](const int curve, const int pos) { + const IndexRange points = points_by_curve[curve]; + const IndexRange bezier_point_range = bezier_offsets[pos]; + for (const int i : points.index_range()) { + const int point = points[i]; + const int bezier_point = bezier_point_range[i]; + curve_or_handle_segments[point] = uint2(handles_left[bezier_point], point); + } + }); - MutableSpan lines_left = lines.slice( - handle_range_left(non_bezier_points_num, bezier_offsets).shift(non_bezier_curves_num)); - MutableSpan lines_right = lines.slice( - handle_range_right(non_bezier_points_num, bezier_offsets).shift(non_bezier_curves_num)); + MutableSpan right_handle_segments = lines.drop_front(points_num); + bezier_curves.foreach_index(GrainSize(512), [&](const int curve, const int pos) { + const IndexRange points = points_by_curve[curve]; + const IndexRange bezier_point_range = bezier_offsets[pos]; + for (const int i : points.index_range()) { + const int point = points[i]; + const int bezier_point = bezier_point_range[i]; + right_handle_segments[bezier_point] = uint2(handles_right[bezier_point], point); + } + }); - bezier_curves.foreach_index(GrainSize(512), [&](const int curve, const int pos) { - const IndexRange points = points_by_curve[curve]; - const IndexRange bezier_point_range = bezier_offsets[pos]; - for (const int i : points.index_range()) { - const int point = points[i]; - const int bezier_point = bezier_point_range[i]; - lines_left[bezier_point] = uint2(handles_left[bezier_point], point); - lines_right[bezier_point] = uint2(handles_right[bezier_point], point); - } - }); - } - - extract_curve_lines(points_by_curve, cyclic, nurbs_curves, cyclic_segment_offset, lines); + BLI_assert(!lines.contains(uint2(std::numeric_limits::min()))); GPU_indexbuf_build_in_place_ex( &builder, 0, handles_and_points_num(points_num, bezier_offsets), false, &ibo);