From cf8e163d9b7f690bf1be7f071ae89f9bed56aa4a Mon Sep 17 00:00:00 2001 From: Casey Bianco-Davis Date: Mon, 26 Aug 2024 21:39:38 -0700 Subject: [PATCH 1/7] GPv3: Use Span of Vector for triangles --- .../blender/blenkernel/BKE_grease_pencil.hh | 4 +- .../blenkernel/intern/grease_pencil.cc | 28 ++++++-------- .../draw/engines/gpencil/gpencil_engine_c.cc | 4 +- .../overlay/overlay_next_grease_pencil.hh | 4 +- .../draw/engines/overlay/overlay_outline.cc | 4 +- .../intern/draw_cache_impl_grease_pencil.cc | 38 ++++++------------- 6 files changed, 34 insertions(+), 48 deletions(-) diff --git a/source/blender/blenkernel/BKE_grease_pencil.hh b/source/blender/blenkernel/BKE_grease_pencil.hh index 6b3efee530b..655492b9c02 100644 --- a/source/blender/blenkernel/BKE_grease_pencil.hh +++ b/source/blender/blenkernel/BKE_grease_pencil.hh @@ -54,7 +54,7 @@ class DrawingRuntime { /** * Triangle cache for all the strokes in the drawing. */ - mutable SharedCache> triangles_cache; + mutable SharedCache>> triangles_cache; /** * Normal vector cache for every stroke. Computed using Newell's method. @@ -89,7 +89,7 @@ class Drawing : public ::GreasePencilDrawing { /** * The triangles for all the fills in the geometry. */ - Span triangles() const; + Span> triangles() const; /** * Normal vectors for a plane that fits the stroke. */ diff --git a/source/blender/blenkernel/intern/grease_pencil.cc b/source/blender/blenkernel/intern/grease_pencil.cc index f618dbff8b7..917d60a4d8c 100644 --- a/source/blender/blenkernel/intern/grease_pencil.cc +++ b/source/blender/blenkernel/intern/grease_pencil.cc @@ -366,7 +366,7 @@ Drawing::~Drawing() this->runtime = nullptr; } -Span Drawing::triangles() const +Span> Drawing::triangles() const { struct LocalMemArena { MemArena *pf_arena = nullptr; @@ -379,24 +379,14 @@ Span Drawing::triangles() const } } }; - this->runtime->triangles_cache.ensure([&](Vector &r_data) { + this->runtime->triangles_cache.ensure([&](Vector> &r_data) { const CurvesGeometry &curves = this->strokes(); const Span positions = curves.evaluated_positions(); const Span normals = this->curve_plane_normals(); const OffsetIndices points_by_curve = curves.evaluated_points_by_curve(); - int total_triangles = 0; - Array tris_offests(curves.curves_num()); - for (int curve_i : curves.curves_range()) { - IndexRange points = points_by_curve[curve_i]; - if (points.size() > 2) { - tris_offests[curve_i] = total_triangles; - total_triangles += points.size() - 2; - } - } - - r_data.resize(total_triangles); - MutableSpan triangles = r_data.as_mutable_span(); + r_data.resize(curves.curves_num()); + MutableSpan> strokes_triangles = r_data.as_mutable_span(); threading::EnumerableThreadSpecific all_local_mem_arenas; threading::parallel_for(curves.curves_range(), 32, [&](const IndexRange range) { MemArena *pf_arena = all_local_mem_arenas.local().pf_arena; @@ -407,7 +397,8 @@ Span Drawing::triangles() const } const int num_triangles = points.size() - 2; - MutableSpan r_tris = triangles.slice(tris_offests[curve_i], num_triangles); + strokes_triangles[curve_i].resize(num_triangles); + MutableSpan r_tris = strokes_triangles[curve_i]; float(*projverts)[2] = static_cast( BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(points.size()))); @@ -415,7 +406,7 @@ Span Drawing::triangles() const float3x3 axis_mat; axis_dominant_v3_to_m3(axis_mat.ptr(), normals[curve_i]); - for (const int i : IndexRange(points.size())) { + for (const int i : points.index_range()) { mul_v2_m3v3(projverts[i], axis_mat.ptr(), positions[points[i]]); } @@ -424,6 +415,11 @@ Span Drawing::triangles() const 0, reinterpret_cast(r_tris.data()), pf_arena); + + for (const int i : r_tris.index_range()) { + r_tris[i] += uint3(points.first()); + } + BLI_memarena_clear(pf_arena); } }); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc index fb75051ed45..52a84f24f34 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc +++ b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc @@ -714,6 +714,8 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData for (const DrawingInfo info : drawings) { const Layer &layer = *layers[info.layer_index]; + const Span> triangles = info.drawing.triangles(); + const bke::CurvesGeometry &curves = info.drawing.strokes(); const OffsetIndices points_by_curve = curves.evaluated_points_by_curve(); const bke::AttributeAccessor attributes = curves.attributes(); @@ -733,7 +735,7 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData int total_num_vertices = 0; visible_strokes.foreach_index([&](const int stroke_i, const int pos) { const IndexRange points = points_by_curve[stroke_i]; - const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0; + const int num_stroke_triangles = triangles[stroke_i].size(); const int num_stroke_vertices = (points.size() + int(cyclic[stroke_i] && (points.size() >= 3))); num_triangles_per_stroke[pos] = num_stroke_triangles; diff --git a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh index 45573c07e51..4bfd0298740 100644 --- a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh +++ b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh @@ -90,6 +90,8 @@ class GreasePencil { const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); + const Span> triangles = info.drawing.triangles(); + visible_strokes.foreach_index([&](const int stroke_i) { const IndexRange points = points_by_curve[stroke_i]; const int material_index = stroke_materials[stroke_i]; @@ -98,7 +100,7 @@ class GreasePencil { const bool hide_onion = info.onion_id != 0; const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; - const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0; + const int num_stroke_triangles = triangles[stroke_i].size(); const int num_stroke_vertices = (points.size() + int(cyclic[stroke_i] && (points.size() >= 3))); diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc index 3c7a0d8f755..e367570a777 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.cc +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -324,6 +324,8 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); + const Span> triangles = info.drawing.triangles(); + visible_strokes.foreach_index([&](const int stroke_i) { const IndexRange points = points_by_curve[stroke_i]; const int material_index = stroke_materials[stroke_i]; @@ -332,7 +334,7 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, const bool hide_onion = info.onion_id != 0; const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; - const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0; + const int num_stroke_triangles = triangles[stroke_i].size(); const int num_stroke_vertices = (points.size() + int(cyclic[stroke_i] && (points.size() >= 3))); diff --git a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc index cfc39f15356..51ffb2eb049 100644 --- a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc +++ b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc @@ -1043,7 +1043,6 @@ static void grease_pencil_geom_batch_ensure(Object &object, int total_triangles_num = 0; int v_offset = 0; Vector> verts_start_offsets_per_visible_drawing; - Vector> tris_start_offsets_per_visible_drawing; for (const ed::greasepencil::DrawingInfo &info : drawings) { const bke::CurvesGeometry &curves = info.drawing.strokes(); const OffsetIndices points_by_curve = curves.evaluated_points_by_curve(); @@ -1054,23 +1053,7 @@ static void grease_pencil_geom_batch_ensure(Object &object, const int num_curves = visible_strokes.size(); const int verts_start_offsets_size = num_curves; - const int tris_start_offsets_size = num_curves; Array verts_start_offsets(verts_start_offsets_size); - Array tris_start_offsets(tris_start_offsets_size); - - /* Calculate the triangle offsets for all the visible curves. */ - int t_offset = 0; - int pos = 0; - for (const int curve_i : curves.curves_range()) { - IndexRange points = points_by_curve[curve_i]; - if (visible_strokes.contains(curve_i)) { - tris_start_offsets[pos] = t_offset; - pos++; - } - if (points.size() >= 3) { - t_offset += points.size() - 2; - } - } /* Calculate the vertex offsets for all the visible curves. */ int num_cyclic = 0; @@ -1091,10 +1074,12 @@ static void grease_pencil_geom_batch_ensure(Object &object, /* One vertex is stored before and after as padding. Cyclic strokes have one extra vertex. */ total_verts_num += num_points + num_cyclic + num_curves * 2; total_triangles_num += (num_points + num_cyclic) * 2; - total_triangles_num += info.drawing.triangles().size(); + + for (const int curve_i : curves.curves_range()) { + total_triangles_num += info.drawing.triangles()[curve_i].size(); + } verts_start_offsets_per_visible_drawing.append(std::move(verts_start_offsets)); - tris_start_offsets_per_visible_drawing.append(std::move(tris_start_offsets)); } GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; @@ -1161,10 +1146,9 @@ static void grease_pencil_geom_batch_ensure(Object &object, const VArray fill_opacities = *attributes.lookup_or_default( "fill_opacity", bke::AttrDomain::Curve, 1.0f); - const Span triangles = info.drawing.triangles(); + const Span> triangles = info.drawing.triangles(); const Span texture_matrices = info.drawing.texture_matrices(); const Span verts_start_offsets = verts_start_offsets_per_visible_drawing[drawing_i]; - const Span tris_start_offsets = tris_start_offsets_per_visible_drawing[drawing_i]; IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( object, info.drawing, memory); @@ -1214,7 +1198,6 @@ static void grease_pencil_geom_batch_ensure(Object &object, const IndexRange points = points_by_curve[curve_i]; const bool is_cyclic = cyclic[curve_i] && (points.size() > 2); const int verts_start_offset = verts_start_offsets[pos]; - const int tris_start_offset = tris_start_offsets[pos]; const int num_verts = 1 + points.size() + (is_cyclic ? 1 : 0) + 1; const IndexRange verts_range = IndexRange(verts_start_offset, num_verts); MutableSpan verts_slice = verts.slice(verts_range); @@ -1228,12 +1211,13 @@ static void grease_pencil_geom_batch_ensure(Object &object, /* If the stroke has more than 2 points, add the triangle indices to the index buffer. */ if (points.size() >= 3) { - const Span tris_slice = triangles.slice(tris_start_offset, points.size() - 2); + const Span tris_slice = triangles[curve_i]; for (const uint3 tri : tris_slice) { - GPU_indexbuf_add_tri_verts(&ibo, - (verts_range[1] + tri.x) << GP_VERTEX_ID_SHIFT, - (verts_range[1] + tri.y) << GP_VERTEX_ID_SHIFT, - (verts_range[1] + tri.z) << GP_VERTEX_ID_SHIFT); + GPU_indexbuf_add_tri_verts( + &ibo, + (verts_range.first() + tri.x - points.first() + 1) << GP_VERTEX_ID_SHIFT, + (verts_range.first() + tri.y - points.first() + 1) << GP_VERTEX_ID_SHIFT, + (verts_range.first() + tri.z - points.first() + 1) << GP_VERTEX_ID_SHIFT); } } -- 2.30.2 From 2f5dbf76f52897a44df72f72e09cb3db56c54a6d Mon Sep 17 00:00:00 2001 From: Casey Bianco-Davis Date: Sat, 31 Aug 2024 20:28:11 -0700 Subject: [PATCH 2/7] GPv3: Add groups and rendering. --- .../blender/blenkernel/BKE_grease_pencil.hh | 3 + .../blenkernel/intern/grease_pencil.cc | 244 +++++++++++++++--- .../draw/engines/gpencil/gpencil_engine_c.cc | 76 ++++-- .../overlay/overlay_next_grease_pencil.hh | 49 ++-- .../draw/engines/overlay/overlay_outline.cc | 50 ++-- .../intern/draw_cache_impl_grease_pencil.cc | 130 +++++----- 6 files changed, 388 insertions(+), 164 deletions(-) diff --git a/source/blender/blenkernel/BKE_grease_pencil.hh b/source/blender/blenkernel/BKE_grease_pencil.hh index 655492b9c02..5031af82462 100644 --- a/source/blender/blenkernel/BKE_grease_pencil.hh +++ b/source/blender/blenkernel/BKE_grease_pencil.hh @@ -86,6 +86,9 @@ class Drawing : public ::GreasePencilDrawing { const bke::CurvesGeometry &strokes() const; bke::CurvesGeometry &strokes_for_write(); + + Array get_shapes_index_masks(IndexMaskMemory &memory) const; + /** * The triangles for all the fills in the geometry. */ diff --git a/source/blender/blenkernel/intern/grease_pencil.cc b/source/blender/blenkernel/intern/grease_pencil.cc index cbc876c4bda..20bb9b1143b 100644 --- a/source/blender/blenkernel/intern/grease_pencil.cc +++ b/source/blender/blenkernel/intern/grease_pencil.cc @@ -29,6 +29,7 @@ #include "BKE_object_types.hh" #include "BLI_bounds.hh" +#include "BLI_delaunay_2d.hh" #include "BLI_enumerable_thread_specific.hh" #include "BLI_map.hh" #include "BLI_math_euler_types.hh" @@ -366,61 +367,234 @@ Drawing::~Drawing() this->runtime = nullptr; } -Span> Drawing::triangles() const +Array Drawing::get_shapes_index_masks(IndexMaskMemory &memory) const { - struct LocalMemArena { - MemArena *pf_arena = nullptr; - LocalMemArena() : pf_arena(BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Drawing::triangles")) {} + const CurvesGeometry &curves = this->strokes(); + const bke::AttributeAccessor attributes = curves.attributes(); - ~LocalMemArena() - { - if (pf_arena != nullptr) { - BLI_memarena_free(pf_arena); + const int num_curves = curves.curves_num(); + + const VArray shape_ids = *attributes.lookup("shape_id", bke::AttrDomain::Curve); + + if (!shape_ids) { + /* If the attribute does not exist then the default is each shape containing one curve. */ + Array data(num_curves); + IndexMask::from_groups( + IndexMask(num_curves), memory, [&](const int i) { return i; }, data); + + return data; + } + + const int max_shape_id = *std::max_element(shape_ids.get_internal_span().begin(), + shape_ids.get_internal_span().end()); + + Array data(max_shape_id + 1); + IndexMask::from_groups( + IndexRange(num_curves), memory, [&](const int i) { return shape_ids[i]; }, data); + + return data; +} + +static bool check_self_intersections(Span projverts) +{ + std::atomic intersect = false; + threading::parallel_for(projverts.index_range(), 512, [&](const IndexRange range) { + for (const int e2_id : range) { + if (intersect) { + return; + } + for (const int e1_id : projverts.index_range().drop_front(e2_id)) { + const int p1 = e1_id; + const int p2 = (e1_id + 1) % projverts.size(); + const int p3 = e2_id; + const int p4 = (e2_id + 1) % projverts.size(); + if (p1 == p4) { + continue; + } + if (p2 == p3) { + continue; + } + + if (isect_seg_seg_v2_simple(projverts[p1], projverts[p2], projverts[p3], projverts[p4])) { + intersect.store(true, std::memory_order_relaxed); + return; + } + } + }; + }); + + return intersect; +} + +static bool check_other_intersections(Span projverts1, Span projverts2) +{ + std::atomic intersect = false; + + threading::parallel_for(projverts1.index_range(), 512, [&](const IndexRange range) { + for (const int e1_id : range) { + for (const int e2_id : projverts2.index_range()) { + const int p11 = e1_id; + const int p12 = (e1_id + 1) % projverts1.size(); + const int p21 = e2_id; + const int p22 = (e2_id + 1) % projverts2.size(); + + if (isect_seg_seg_v2_simple( + projverts1[p11], projverts1[p12], projverts2[p21], projverts2[p22])) + { + intersect.store(true, std::memory_order_relaxed); + return; + } } } - }; + }); + + return intersect; +} + +static bool check_valid_curves(Span projverts, const OffsetIndices points_by_group) +{ + std::atomic intersect = false; + /* Check for self intersections. */ + threading::parallel_for(points_by_group.index_range(), 512, [&](const IndexRange range) { + for (const int pos : range) { + if (intersect) { + return; + } + const IndexRange point_group = points_by_group[pos]; + if (check_self_intersections(projverts.slice(point_group))) { + intersect.store(true, std::memory_order_relaxed); + return; + } + } + }); + + if (intersect) { + return false; + } + + /* Check if other intersect. */ + threading::parallel_for(points_by_group.index_range(), 512, [&](const IndexRange range1) { + for (const int pos1 : range1) { + if (intersect) { + return; + } + const IndexRange point_group1 = points_by_group[pos1]; + + threading::parallel_for(points_by_group.index_range(), 512, [&](const IndexRange range2) { + for (const int pos2 : range2) { + if (intersect) { + return; + } + const IndexRange point_group2 = points_by_group[pos2]; + + if (pos2 >= pos1) { + return; + } + if (check_other_intersections(projverts.slice(point_group1), + projverts.slice(point_group2))) + { + intersect.store(true, std::memory_order_relaxed); + return; + } + } + }); + } + }); + + if (intersect) { + return false; + } + + return true; +} + +Span> Drawing::triangles() const +{ this->runtime->triangles_cache.ensure([&](Vector> &r_data) { const CurvesGeometry &curves = this->strokes(); const Span positions = curves.evaluated_positions(); const Span normals = this->curve_plane_normals(); const OffsetIndices points_by_curve = curves.evaluated_points_by_curve(); + const Array point_to_curve_map = curves.point_to_curve_map(); - r_data.resize(curves.curves_num()); + IndexMaskMemory memory; + const Array groups = this->get_shapes_index_masks(memory); + + r_data.resize(groups.size() + 1); + + // r_data.resize(curves.curves_num()); MutableSpan> strokes_triangles = r_data.as_mutable_span(); - threading::EnumerableThreadSpecific all_local_mem_arenas; - threading::parallel_for(curves.curves_range(), 32, [&](const IndexRange range) { - MemArena *pf_arena = all_local_mem_arenas.local().pf_arena; - for (const int curve_i : range) { - const IndexRange points = points_by_curve[curve_i]; - if (points.size() < 3) { + + threading::parallel_for(groups.index_range(), 32, [&](const IndexRange group_range) { + for (const int group_id : group_range) { + const IndexMask &group = groups[group_id]; + + float3x3 axis_mat; + axis_dominant_v3_to_m3(axis_mat.ptr(), normals[group.first()]); + + Array offsets_data(group.size() + 1); + offset_indices::gather_group_sizes( + points_by_curve, group, offsets_data.as_mutable_span().drop_back(1)); + offset_indices::accumulate_counts_to_offsets(offsets_data); + const OffsetIndices points_by_group = OffsetIndices(offsets_data); + + const int num_points = points_by_group.total_size(); + + Array projverts2(num_points); + group.foreach_index(GrainSize(256), [&](const int64_t curve_i, const int64_t pos) { + const IndexRange point_group = points_by_group[pos]; + const IndexRange points = points_by_curve[curve_i]; + threading::parallel_for(points.index_range(), 512, [&](const IndexRange range) { + for (const int p_id : range) { + mul_v2_m3v3(projverts2[point_group[p_id]], axis_mat.ptr(), positions[points[p_id]]); + } + }); + }); + + if (!check_valid_curves(projverts2, points_by_group)) { continue; } - const int num_triangles = points.size() - 2; - strokes_triangles[curve_i].resize(num_triangles); - MutableSpan r_tris = strokes_triangles[curve_i]; + Array verts(num_points); + Array> edges(num_points); + Array> faces(group.size()); - float(*projverts)[2] = static_cast( - BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(points.size()))); + Array vert_to_point_map(num_points); - float3x3 axis_mat; - axis_dominant_v3_to_m3(axis_mat.ptr(), normals[curve_i]); + group.foreach_index(GrainSize(256), [&](const int64_t curve_i, const int64_t pos) { + const IndexRange point_group = points_by_group[pos]; + const IndexRange points = points_by_curve[curve_i]; + faces[pos].resize(points.size()); + threading::parallel_for(points.index_range(), 512, [&](const IndexRange range) { + for (const int p_id : range) { + vert_to_point_map[point_group[p_id]] = points[p_id]; + verts[point_group[p_id]] = double2(projverts2[point_group[p_id]]); + edges[point_group[p_id]] = std::pair( + point_group[p_id], point_group[(p_id + 1) % points.size()]); + faces[pos][p_id] = point_group[p_id]; + } + }); + }); - for (const int i : points.index_range()) { - mul_v2_m3v3(projverts[i], axis_mat.ptr(), positions[points[i]]); - } + meshintersect::CDT_input input; + input.vert = verts; + input.edge = edges; + input.face = faces; + input.need_ids = false; - BLI_polyfill_calc_arena(projverts, - points.size(), - 0, - reinterpret_cast(r_tris.data()), - pf_arena); + meshintersect::CDT_result result = delaunay_2d_calc(input, CDT_INSIDE_WITH_HOLES); - for (const int i : r_tris.index_range()) { - r_tris[i] += uint3(points.first()); - } + strokes_triangles[group_id].resize(result.face.size()); + MutableSpan r_tris = strokes_triangles[group_id]; - BLI_memarena_clear(pf_arena); + threading::parallel_for(result.face.index_range(), 512, [&](const IndexRange range) { + for (const int i : range) { + BLI_assert(result.face[i].size() == 3); + r_tris[i] = uint3(vert_to_point_map[result.face[i][0]], + vert_to_point_map[result.face[i][1]], + vert_to_point_map[result.face[i][2]]); + } + }); } }); }); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc index 52a84f24f34..bce7422ff64 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc +++ b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc @@ -725,24 +725,32 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); + const Array groups = info.drawing.get_shapes_index_masks(memory); /* Precompute all the triangle and vertex counts. * In case the drawing should not be rendered, we need to compute the offset where the next * drawing begins. */ - Array num_triangles_per_stroke(visible_strokes.size()); + Array num_triangles_per_stroke(groups.size()); Array num_vertices_per_stroke(visible_strokes.size()); int total_num_triangles = 0; int total_num_vertices = 0; - visible_strokes.foreach_index([&](const int stroke_i, const int pos) { - const IndexRange points = points_by_curve[stroke_i]; - const int num_stroke_triangles = triangles[stroke_i].size(); - const int num_stroke_vertices = (points.size() + - int(cyclic[stroke_i] && (points.size() >= 3))); - num_triangles_per_stroke[pos] = num_stroke_triangles; - num_vertices_per_stroke[pos] = num_stroke_vertices; + int current_curve = 0; + for (const int group_id : groups.index_range()) { + const IndexMask &group = groups[group_id]; + + const int num_stroke_triangles = triangles[group_id].size(); + num_triangles_per_stroke[group_id] = num_stroke_triangles; total_num_triangles += num_stroke_triangles; - total_num_vertices += num_stroke_vertices; - }); + + group.foreach_index([&](const int curve_i) { + const IndexRange points = points_by_curve[curve_i]; + const int num_stroke_vertices = (points.size() + + int(cyclic[curve_i] && (points.size() >= 3))); + num_vertices_per_stroke[current_curve] = num_stroke_vertices; + total_num_vertices += num_stroke_vertices; + current_curve++; + }); + } bool is_layer_used_as_mask = false; const bool show_drawing_in_render = use_layer_in_render( @@ -789,17 +797,21 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData info.frame_number != pd->cfra && pd->use_multiedit_lines_only; const bool is_onion = info.onion_id != 0; - visible_strokes.foreach_index([&](const int stroke_i, const int pos) { - const IndexRange points = points_by_curve[stroke_i]; + current_curve = 0; + for (const int group_id : groups.index_range()) { + const IndexMask &group = groups[group_id]; + + const int curve_i = group.first(); + /* The material index is allowed to be negative as it's stored as a generic attribute. We - * clamp it here to avoid crashing in the rendering code. Any stroke with a material < 0 will - * use the first material in the first material slot.*/ - const int material_index = std::max(stroke_materials[stroke_i], 0); + * clamp it here to avoid crashing in the rendering code. Any stroke with a material < 0 + * will use the first material in the first material slot.*/ + const int material_index = std::max(stroke_materials[curve_i], 0); const MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1); const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; const bool show_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0); - const bool show_fill = (points.size() >= 3) && + const bool show_fill = (!triangles[group_id].is_empty()) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0) && (!pd->simplify_fill); const bool hide_onion = is_onion && ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0 || @@ -808,9 +820,12 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData (only_lines && !is_onion) || hide_onion; if (skip_stroke) { - t_offset += num_triangles_per_stroke[pos]; - t_offset += num_vertices_per_stroke[pos] * 2; - return; + t_offset += num_triangles_per_stroke[group_id]; + for (const int i : group.index_range()) { + t_offset += num_vertices_per_stroke[current_curve + i] * 2; + }; + current_curve += group.size(); + continue; } GPUUniformBuf *new_ubo_mat; @@ -855,20 +870,25 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData if (show_fill) { const int v_first = t_offset * 3; - const int v_count = num_triangles_per_stroke[pos] * 3; + const int v_count = num_triangles_per_stroke[group_id] * 3; drawcall_add(geom, v_first, v_count); } - t_offset += num_triangles_per_stroke[pos]; + t_offset += num_triangles_per_stroke[group_id]; - if (show_stroke) { - const int v_first = t_offset * 3; - const int v_count = num_vertices_per_stroke[pos] * 2 * 3; - drawcall_add(geom, v_first, v_count); - } + group.foreach_index([&](const int curve_i) { + const IndexRange points = points_by_curve[curve_i]; - t_offset += num_vertices_per_stroke[pos] * 2; - }); + if (show_stroke) { + const int v_first = t_offset * 3; + const int v_count = num_vertices_per_stroke[current_curve] * 2 * 3; + drawcall_add(geom, v_first, v_count); + } + + t_offset += num_vertices_per_stroke[current_curve] * 2; + current_curve++; + }); + } } drawcall_flush(); diff --git a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh index 4bfd0298740..89efc35eae6 100644 --- a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh +++ b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh @@ -89,33 +89,32 @@ class GreasePencil { IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); + const Array groups = info.drawing.get_shapes_index_masks(memory); const Span> triangles = info.drawing.triangles(); - visible_strokes.foreach_index([&](const int stroke_i) { - const IndexRange points = points_by_curve[stroke_i]; - const int material_index = stroke_materials[stroke_i]; + const bool hide_onion = info.onion_id != 0; + + for (const int group_id : groups.index_range()) { + const IndexMask &group = groups[group_id]; + + const int material_index = stroke_materials[group.first()]; MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1); - const bool hide_onion = info.onion_id != 0; const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; - const int num_stroke_triangles = triangles[stroke_i].size(); - const int num_stroke_vertices = (points.size() + - int(cyclic[stroke_i] && (points.size() >= 3))); + const int num_stroke_triangles = triangles[group_id].size(); if (hide_material || hide_onion) { t_offset += num_stroke_triangles; - t_offset += num_stroke_vertices * 2; - return; } - blender::gpu::Batch *geom = draw::DRW_cache_grease_pencil_get(scene, ob); - const bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; - const bool show_fill = (points.size() >= 3) && + const bool show_fill = (num_stroke_triangles != 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; + blender::gpu::Batch *geom = draw::DRW_cache_grease_pencil_get(scene, ob); + if (show_fill) { int v_first = t_offset * 3; int v_count = num_stroke_triangles * 3; @@ -124,13 +123,25 @@ class GreasePencil { t_offset += num_stroke_triangles; - if (show_stroke) { - int v_first = t_offset * 3; - int v_count = num_stroke_vertices * 2 * 3; - pass.draw(geom, 1, v_count, v_first, res_handle); - } - t_offset += num_stroke_vertices * 2; - }); + group.foreach_index([&](const int curve_i) { + const IndexRange points = points_by_curve[curve_i]; + + const int num_stroke_vertices = (points.size() + + int(cyclic[curve_i] && (points.size() >= 3))); + + if (hide_material || hide_onion) { + t_offset += num_stroke_vertices * 2; + return; + } + + if (show_stroke) { + int v_first = t_offset * 3; + int v_count = num_stroke_vertices * 2 * 3; + pass.draw(geom, 1, v_count, v_first, res_handle); + } + t_offset += num_stroke_vertices * 2; + }); + } } } diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc index e367570a777..210c90e0e77 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.cc +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -323,31 +323,26 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); + const Array groups = info.drawing.get_shapes_index_masks(memory); const Span> triangles = info.drawing.triangles(); - visible_strokes.foreach_index([&](const int stroke_i) { - const IndexRange points = points_by_curve[stroke_i]; - const int material_index = stroke_materials[stroke_i]; + for (const int group_id : groups.index_range()) { + const IndexMask &group = groups[group_id]; + + const int material_index = stroke_materials[group.first()]; MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1); const bool hide_onion = info.onion_id != 0; const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; - const int num_stroke_triangles = triangles[stroke_i].size(); - const int num_stroke_vertices = (points.size() + - int(cyclic[stroke_i] && (points.size() >= 3))); - - if (hide_material || hide_onion) { - t_offset += num_stroke_triangles; - t_offset += num_stroke_vertices * 2; - return; - } - - blender::gpu::Batch *geom = draw::DRW_cache_grease_pencil_get(scene, ob); + const int num_stroke_triangles = triangles[group_id].size(); const bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; - const bool show_fill = (points.size() >= 3) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; + const bool show_fill = (num_stroke_triangles != 0) && + (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; + + blender::gpu::Batch *geom = draw::DRW_cache_grease_pencil_get(scene, ob); if (show_fill) { int v_first = t_offset * 3; @@ -357,13 +352,24 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, t_offset += num_stroke_triangles; - if (show_stroke) { - int v_first = t_offset * 3; - int v_count = num_stroke_vertices * 2 * 3; - DRW_shgroup_call_range(grp, ob, geom, v_first, v_count); - } - t_offset += num_stroke_vertices * 2; - }); + group.foreach_index([&](const int curve_i) { + const IndexRange points = points_by_curve[curve_i]; + const int num_stroke_vertices = (points.size() + + int(cyclic[curve_i] && (points.size() >= 3))); + + if (hide_material || hide_onion) { + t_offset += num_stroke_vertices * 2; + return; + } + + if (show_stroke) { + int v_first = t_offset * 3; + int v_count = num_stroke_vertices * 2 * 3; + DRW_shgroup_call_range(grp, ob, geom, v_first, v_count); + } + t_offset += num_stroke_vertices * 2; + }); + } } } diff --git a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc index 51ffb2eb049..55710854f90 100644 --- a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc +++ b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc @@ -1075,8 +1075,8 @@ static void grease_pencil_geom_batch_ensure(Object &object, total_verts_num += num_points + num_cyclic + num_curves * 2; total_triangles_num += (num_points + num_cyclic) * 2; - for (const int curve_i : curves.curves_range()) { - total_triangles_num += info.drawing.triangles()[curve_i].size(); + for (const int group_id : info.drawing.triangles().index_range()) { + total_triangles_num += info.drawing.triangles()[group_id].size(); } verts_start_offsets_per_visible_drawing.append(std::move(verts_start_offsets)); @@ -1194,70 +1194,80 @@ static void grease_pencil_geom_batch_ensure(Object &object, GPU_indexbuf_add_tri_verts(&ibo, v_mat + 2, v_mat + 1, v_mat + 3); }; - visible_strokes.foreach_index([&](const int curve_i, const int pos) { - const IndexRange points = points_by_curve[curve_i]; - const bool is_cyclic = cyclic[curve_i] && (points.size() > 2); - const int verts_start_offset = verts_start_offsets[pos]; - const int num_verts = 1 + points.size() + (is_cyclic ? 1 : 0) + 1; - const IndexRange verts_range = IndexRange(verts_start_offset, num_verts); - MutableSpan verts_slice = verts.slice(verts_range); - MutableSpan cols_slice = cols.slice(verts_range); - const float4x2 texture_matrix = texture_matrices[curve_i] * object_space_to_layer_space; + const Array groups = info.drawing.get_shapes_index_masks(memory); + const Array point_to_curve_map = curves.point_to_curve_map(); - const Span lengths = curves.evaluated_lengths_for_curve(curve_i, cyclic[curve_i]); + auto point_to_id = [&](uint32_t p) { + const int curve_ = point_to_curve_map[p]; + const IndexRange points_ = points_by_curve[curve_]; + return (1 + (p - points_.first()) + verts_start_offsets[curve_]) << GP_VERTEX_ID_SHIFT; + }; - /* First vertex is not drawn. */ - verts_slice.first().mat = -1; + for (const int group_id : groups.index_range()) { + const IndexMask &group = groups[group_id]; + const Span tris_slice = triangles[group_id]; - /* If the stroke has more than 2 points, add the triangle indices to the index buffer. */ - if (points.size() >= 3) { - const Span tris_slice = triangles[curve_i]; - for (const uint3 tri : tris_slice) { - GPU_indexbuf_add_tri_verts( - &ibo, - (verts_range.first() + tri.x - points.first() + 1) << GP_VERTEX_ID_SHIFT, - (verts_range.first() + tri.y - points.first() + 1) << GP_VERTEX_ID_SHIFT, - (verts_range.first() + tri.z - points.first() + 1) << GP_VERTEX_ID_SHIFT); + /* Add the triangle indices to the index buffer. */ + // if (tris_slice.size() != 0) { + for (const uint3 tri : tris_slice) { + const uint3 tri_verts = uint3(point_to_id(tri.x), point_to_id(tri.y), point_to_id(tri.z)); + GPU_indexbuf_add_tri_verts(&ibo, tri_verts.x, tri_verts.y, tri_verts.z); + } + // } + + group.foreach_index([&](const int curve_i) { + const IndexRange points = points_by_curve[curve_i]; + const bool is_cyclic = cyclic[curve_i] && (points.size() > 2); + const int verts_start_offset = verts_start_offsets[curve_i]; + const int num_verts = 1 + points.size() + (is_cyclic ? 1 : 0) + 1; + const IndexRange verts_range = IndexRange(verts_start_offset, num_verts); + MutableSpan verts_slice = verts.slice(verts_range); + MutableSpan cols_slice = cols.slice(verts_range); + const float4x2 texture_matrix = texture_matrices[curve_i] * object_space_to_layer_space; + + const Span lengths = curves.evaluated_lengths_for_curve(curve_i, cyclic[curve_i]); + + /* First vertex is not drawn. */ + verts_slice.first().mat = -1; + + /* Write all the point attributes to the vertex buffers. Create a quad for each point. */ + const float u_scale = u_scales[curve_i]; + const float u_translation = u_translations[curve_i]; + for (const int i : IndexRange(points.size())) { + const int idx = i + 1; + const float u_stroke = u_scale * (i > 0 ? lengths[i - 1] : 0.0f) + u_translation; + populate_point(verts_range, + curve_i, + start_caps[curve_i], + end_caps[curve_i], + points[i], + idx, + u_stroke, + texture_matrix, + verts_slice[idx], + cols_slice[idx]); } - } - /* Write all the point attributes to the vertex buffers. Create a quad for each point. */ - const float u_scale = u_scales[curve_i]; - const float u_translation = u_translations[curve_i]; - for (const int i : IndexRange(points.size())) { - const int idx = i + 1; - const float u_stroke = u_scale * (i > 0 ? lengths[i - 1] : 0.0f) + u_translation; - populate_point(verts_range, - curve_i, - start_caps[curve_i], - end_caps[curve_i], - points[i], - idx, - u_stroke, - texture_matrix, - verts_slice[idx], - cols_slice[idx]); - } + if (is_cyclic) { + const int idx = points.size() + 1; + const float u = points.size() > 1 ? lengths[points.size() - 1] : 0.0f; + const float u_stroke = u_scale * u + u_translation; + populate_point(verts_range, + curve_i, + start_caps[curve_i], + end_caps[curve_i], + points[0], + idx, + u_stroke, + texture_matrix, + verts_slice[idx], + cols_slice[idx]); + } - if (is_cyclic) { - const int idx = points.size() + 1; - const float u = points.size() > 1 ? lengths[points.size() - 1] : 0.0f; - const float u_stroke = u_scale * u + u_translation; - populate_point(verts_range, - curve_i, - start_caps[curve_i], - end_caps[curve_i], - points[0], - idx, - u_stroke, - texture_matrix, - verts_slice[idx], - cols_slice[idx]); - } - - /* Last vertex is not drawn. */ - verts_slice.last().mat = -1; - }); + /* Last vertex is not drawn. */ + verts_slice.last().mat = -1; + }); + } } /* Mark last 2 verts as invalid. */ -- 2.30.2 From 75002ef8929ec18899b09c173e1befbe88164cbc Mon Sep 17 00:00:00 2001 From: Casey Bianco-Davis Date: Sat, 31 Aug 2024 21:46:27 -0700 Subject: [PATCH 3/7] Use MemArena --- .../blenkernel/intern/grease_pencil.cc | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/grease_pencil.cc b/source/blender/blenkernel/intern/grease_pencil.cc index 20bb9b1143b..1da3179f00c 100644 --- a/source/blender/blenkernel/intern/grease_pencil.cc +++ b/source/blender/blenkernel/intern/grease_pencil.cc @@ -510,6 +510,18 @@ static bool check_valid_curves(Span projverts, const OffsetIndices Span> Drawing::triangles() const { + struct LocalMemArena { + MemArena *pf_arena = nullptr; + LocalMemArena() : pf_arena(BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Drawing::triangles")) {} + + ~LocalMemArena() + { + if (pf_arena != nullptr) { + BLI_memarena_free(pf_arena); + } + } + }; + this->runtime->triangles_cache.ensure([&](Vector> &r_data) { const CurvesGeometry &curves = this->strokes(); const Span positions = curves.evaluated_positions(); @@ -521,11 +533,11 @@ Span> Drawing::triangles() const const Array groups = this->get_shapes_index_masks(memory); r_data.resize(groups.size() + 1); - - // r_data.resize(curves.curves_num()); MutableSpan> strokes_triangles = r_data.as_mutable_span(); + threading::EnumerableThreadSpecific all_local_mem_arenas; threading::parallel_for(groups.index_range(), 32, [&](const IndexRange group_range) { + MemArena *pf_arena = all_local_mem_arenas.local().pf_arena; for (const int group_id : group_range) { const IndexMask &group = groups[group_id]; @@ -540,18 +552,38 @@ Span> Drawing::triangles() const const int num_points = points_by_group.total_size(); - Array projverts2(num_points); + float(*projverts)[2] = static_cast( + BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(num_points))); + group.foreach_index(GrainSize(256), [&](const int64_t curve_i, const int64_t pos) { const IndexRange point_group = points_by_group[pos]; const IndexRange points = points_by_curve[curve_i]; threading::parallel_for(points.index_range(), 512, [&](const IndexRange range) { for (const int p_id : range) { - mul_v2_m3v3(projverts2[point_group[p_id]], axis_mat.ptr(), positions[points[p_id]]); + mul_v2_m3v3(projverts[point_group[p_id]], axis_mat.ptr(), positions[points[p_id]]); } }); }); - if (!check_valid_curves(projverts2, points_by_group)) { + /* If there is only on stroke or the geometry can not meshed then use simple poly fill + * using the first curve in the group. */ + if (group.size() == 1 || + !check_valid_curves({reinterpret_cast(projverts), num_points}, + points_by_group)) + { + const IndexRange points = points_by_curve[group.first()]; + + strokes_triangles[group_id].resize(points.size() - 2); + MutableSpan r_tris = strokes_triangles[group_id]; + BLI_polyfill_calc_arena(projverts, + points.size(), + 0, + reinterpret_cast(r_tris.data()), + pf_arena); + for (const int i : r_tris.index_range()) { + r_tris[i] += points.first(); + } + BLI_memarena_clear(pf_arena); continue; } @@ -568,7 +600,7 @@ Span> Drawing::triangles() const threading::parallel_for(points.index_range(), 512, [&](const IndexRange range) { for (const int p_id : range) { vert_to_point_map[point_group[p_id]] = points[p_id]; - verts[point_group[p_id]] = double2(projverts2[point_group[p_id]]); + verts[point_group[p_id]] = double2(projverts[point_group[p_id]]); edges[point_group[p_id]] = std::pair( point_group[p_id], point_group[(p_id + 1) % points.size()]); faces[pos][p_id] = point_group[p_id]; -- 2.30.2 From f3cee0eaefc326a94d3bd6c08e11e54f82e86875 Mon Sep 17 00:00:00 2001 From: Casey Bianco-Davis Date: Sun, 1 Sep 2024 09:35:25 -0700 Subject: [PATCH 4/7] Cleanup: Fix: uvs. --- source/blender/draw/intern/draw_cache_impl_grease_pencil.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc index 55710854f90..98dba9b8181 100644 --- a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc +++ b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc @@ -1208,12 +1208,13 @@ static void grease_pencil_geom_batch_ensure(Object &object, const Span tris_slice = triangles[group_id]; /* Add the triangle indices to the index buffer. */ - // if (tris_slice.size() != 0) { for (const uint3 tri : tris_slice) { const uint3 tri_verts = uint3(point_to_id(tri.x), point_to_id(tri.y), point_to_id(tri.z)); GPU_indexbuf_add_tri_verts(&ibo, tri_verts.x, tri_verts.y, tri_verts.z); } - // } + + const float4x2 texture_matrix = texture_matrices[group.first()] * + object_space_to_layer_space; group.foreach_index([&](const int curve_i) { const IndexRange points = points_by_curve[curve_i]; @@ -1223,7 +1224,6 @@ static void grease_pencil_geom_batch_ensure(Object &object, const IndexRange verts_range = IndexRange(verts_start_offset, num_verts); MutableSpan verts_slice = verts.slice(verts_range); MutableSpan cols_slice = cols.slice(verts_range); - const float4x2 texture_matrix = texture_matrices[curve_i] * object_space_to_layer_space; const Span lengths = curves.evaluated_lengths_for_curve(curve_i, cyclic[curve_i]); -- 2.30.2 From 54f486be67b0a2102e57f805d4763490e6ca3bd3 Mon Sep 17 00:00:00 2001 From: Casey Bianco-Davis Date: Sun, 1 Sep 2024 10:26:17 -0700 Subject: [PATCH 5/7] Cleanup: Use unique indices. --- .../blender/blenkernel/BKE_grease_pencil.hh | 2 +- .../blenkernel/intern/grease_pencil.cc | 25 ++++++++----------- .../draw/engines/gpencil/gpencil_engine_c.cc | 2 +- .../overlay/overlay_next_grease_pencil.hh | 2 +- .../draw/engines/overlay/overlay_outline.cc | 2 +- .../intern/draw_cache_impl_grease_pencil.cc | 2 +- 6 files changed, 15 insertions(+), 20 deletions(-) diff --git a/source/blender/blenkernel/BKE_grease_pencil.hh b/source/blender/blenkernel/BKE_grease_pencil.hh index 5031af82462..b28053904b4 100644 --- a/source/blender/blenkernel/BKE_grease_pencil.hh +++ b/source/blender/blenkernel/BKE_grease_pencil.hh @@ -87,7 +87,7 @@ class Drawing : public ::GreasePencilDrawing { const bke::CurvesGeometry &strokes() const; bke::CurvesGeometry &strokes_for_write(); - Array get_shapes_index_masks(IndexMaskMemory &memory) const; + Vector get_shapes_index_masks(IndexMaskMemory &memory) const; /** * The triangles for all the fills in the geometry. diff --git a/source/blender/blenkernel/intern/grease_pencil.cc b/source/blender/blenkernel/intern/grease_pencil.cc index 1da3179f00c..2a123d5c0e3 100644 --- a/source/blender/blenkernel/intern/grease_pencil.cc +++ b/source/blender/blenkernel/intern/grease_pencil.cc @@ -367,32 +367,27 @@ Drawing::~Drawing() this->runtime = nullptr; } -Array Drawing::get_shapes_index_masks(IndexMaskMemory &memory) const +Vector Drawing::get_shapes_index_masks(IndexMaskMemory &memory) const { const CurvesGeometry &curves = this->strokes(); const bke::AttributeAccessor attributes = curves.attributes(); - const int num_curves = curves.curves_num(); - const VArray shape_ids = *attributes.lookup("shape_id", bke::AttrDomain::Curve); if (!shape_ids) { /* If the attribute does not exist then the default is each shape containing one curve. */ - Array data(num_curves); - IndexMask::from_groups( - IndexMask(num_curves), memory, [&](const int i) { return i; }, data); + Vector shapes; + for (const int i : curves.curves_range()) { + shapes.append(IndexRange::from_single(i)); + } - return data; + return shapes; } - const int max_shape_id = *std::max_element(shape_ids.get_internal_span().begin(), - shape_ids.get_internal_span().end()); + VectorSet shape_indexing; + const Vector shapes = IndexMask::from_group_ids(shape_ids, memory, shape_indexing); - Array data(max_shape_id + 1); - IndexMask::from_groups( - IndexRange(num_curves), memory, [&](const int i) { return shape_ids[i]; }, data); - - return data; + return shapes; } static bool check_self_intersections(Span projverts) @@ -530,7 +525,7 @@ Span> Drawing::triangles() const const Array point_to_curve_map = curves.point_to_curve_map(); IndexMaskMemory memory; - const Array groups = this->get_shapes_index_masks(memory); + const Vector groups = this->get_shapes_index_masks(memory); r_data.resize(groups.size() + 1); MutableSpan> strokes_triangles = r_data.as_mutable_span(); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc index bce7422ff64..7d7c3e29158 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc +++ b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc @@ -725,7 +725,7 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); - const Array groups = info.drawing.get_shapes_index_masks(memory); + const Vector groups = info.drawing.get_shapes_index_masks(memory); /* Precompute all the triangle and vertex counts. * In case the drawing should not be rendered, we need to compute the offset where the next diff --git a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh index 89efc35eae6..2d247884e74 100644 --- a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh +++ b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh @@ -89,7 +89,7 @@ class GreasePencil { IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); - const Array groups = info.drawing.get_shapes_index_masks(memory); + const Vector groups = info.drawing.get_shapes_index_masks(memory); const Span> triangles = info.drawing.triangles(); diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc index 210c90e0e77..6caeb6a57ee 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.cc +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -323,7 +323,7 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); - const Array groups = info.drawing.get_shapes_index_masks(memory); + const Vector groups = info.drawing.get_shapes_index_masks(memory); const Span> triangles = info.drawing.triangles(); diff --git a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc index 98dba9b8181..a569167f78f 100644 --- a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc +++ b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc @@ -1194,7 +1194,7 @@ static void grease_pencil_geom_batch_ensure(Object &object, GPU_indexbuf_add_tri_verts(&ibo, v_mat + 2, v_mat + 1, v_mat + 3); }; - const Array groups = info.drawing.get_shapes_index_masks(memory); + const Vector groups = info.drawing.get_shapes_index_masks(memory); const Array point_to_curve_map = curves.point_to_curve_map(); auto point_to_id = [&](uint32_t p) { -- 2.30.2 From 8a7bc5b7baaa3fdaff966d5cafa4518b13df86de Mon Sep 17 00:00:00 2001 From: Casey Bianco-Davis Date: Sun, 1 Sep 2024 10:42:54 -0700 Subject: [PATCH 6/7] Cleanup: Rename `group` to `shape` --- .../blender/blenkernel/BKE_grease_pencil.hh | 3 +- .../blenkernel/intern/grease_pencil.cc | 36 +++++++++---------- .../draw/engines/gpencil/gpencil_engine_c.cc | 34 +++++++++--------- .../overlay/overlay_next_grease_pencil.hh | 12 +++---- .../draw/engines/overlay/overlay_outline.cc | 12 +++---- .../intern/draw_cache_impl_grease_pencil.cc | 12 +++---- 6 files changed, 55 insertions(+), 54 deletions(-) diff --git a/source/blender/blenkernel/BKE_grease_pencil.hh b/source/blender/blenkernel/BKE_grease_pencil.hh index b28053904b4..780a70d1456 100644 --- a/source/blender/blenkernel/BKE_grease_pencil.hh +++ b/source/blender/blenkernel/BKE_grease_pencil.hh @@ -87,10 +87,11 @@ class Drawing : public ::GreasePencilDrawing { const bke::CurvesGeometry &strokes() const; bke::CurvesGeometry &strokes_for_write(); - Vector get_shapes_index_masks(IndexMaskMemory &memory) const; + Vector shapes(IndexMaskMemory &memory) const; /** * The triangles for all the fills in the geometry. + * Stored per shape and indexing into points. */ Span> triangles() const; /** diff --git a/source/blender/blenkernel/intern/grease_pencil.cc b/source/blender/blenkernel/intern/grease_pencil.cc index 2a123d5c0e3..04350da0c7d 100644 --- a/source/blender/blenkernel/intern/grease_pencil.cc +++ b/source/blender/blenkernel/intern/grease_pencil.cc @@ -367,7 +367,7 @@ Drawing::~Drawing() this->runtime = nullptr; } -Vector Drawing::get_shapes_index_masks(IndexMaskMemory &memory) const +Vector Drawing::shapes(IndexMaskMemory &memory) const { const CurvesGeometry &curves = this->strokes(); const bke::AttributeAccessor attributes = curves.attributes(); @@ -525,23 +525,23 @@ Span> Drawing::triangles() const const Array point_to_curve_map = curves.point_to_curve_map(); IndexMaskMemory memory; - const Vector groups = this->get_shapes_index_masks(memory); + const Vector shapes = this->shapes(memory); - r_data.resize(groups.size() + 1); + r_data.resize(shapes.size() + 1); MutableSpan> strokes_triangles = r_data.as_mutable_span(); threading::EnumerableThreadSpecific all_local_mem_arenas; - threading::parallel_for(groups.index_range(), 32, [&](const IndexRange group_range) { + threading::parallel_for(shapes.index_range(), 32, [&](const IndexRange shape_range) { MemArena *pf_arena = all_local_mem_arenas.local().pf_arena; - for (const int group_id : group_range) { - const IndexMask &group = groups[group_id]; + for (const int shape_index : shape_range) { + const IndexMask &shape = shapes[shape_index]; float3x3 axis_mat; - axis_dominant_v3_to_m3(axis_mat.ptr(), normals[group.first()]); + axis_dominant_v3_to_m3(axis_mat.ptr(), normals[shape.first()]); - Array offsets_data(group.size() + 1); + Array offsets_data(shape.size() + 1); offset_indices::gather_group_sizes( - points_by_curve, group, offsets_data.as_mutable_span().drop_back(1)); + points_by_curve, shape, offsets_data.as_mutable_span().drop_back(1)); offset_indices::accumulate_counts_to_offsets(offsets_data); const OffsetIndices points_by_group = OffsetIndices(offsets_data); @@ -550,7 +550,7 @@ Span> Drawing::triangles() const float(*projverts)[2] = static_cast( BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(num_points))); - group.foreach_index(GrainSize(256), [&](const int64_t curve_i, const int64_t pos) { + shape.foreach_index(GrainSize(256), [&](const int64_t curve_i, const int64_t pos) { const IndexRange point_group = points_by_group[pos]; const IndexRange points = points_by_curve[curve_i]; threading::parallel_for(points.index_range(), 512, [&](const IndexRange range) { @@ -562,14 +562,14 @@ Span> Drawing::triangles() const /* If there is only on stroke or the geometry can not meshed then use simple poly fill * using the first curve in the group. */ - if (group.size() == 1 || + if (shape.size() == 1 || !check_valid_curves({reinterpret_cast(projverts), num_points}, points_by_group)) { - const IndexRange points = points_by_curve[group.first()]; + const IndexRange points = points_by_curve[shape.first()]; - strokes_triangles[group_id].resize(points.size() - 2); - MutableSpan r_tris = strokes_triangles[group_id]; + strokes_triangles[shape_index].resize(points.size() - 2); + MutableSpan r_tris = strokes_triangles[shape_index]; BLI_polyfill_calc_arena(projverts, points.size(), 0, @@ -584,11 +584,11 @@ Span> Drawing::triangles() const Array verts(num_points); Array> edges(num_points); - Array> faces(group.size()); + Array> faces(shape.size()); Array vert_to_point_map(num_points); - group.foreach_index(GrainSize(256), [&](const int64_t curve_i, const int64_t pos) { + shape.foreach_index(GrainSize(256), [&](const int64_t curve_i, const int64_t pos) { const IndexRange point_group = points_by_group[pos]; const IndexRange points = points_by_curve[curve_i]; faces[pos].resize(points.size()); @@ -611,8 +611,8 @@ Span> Drawing::triangles() const meshintersect::CDT_result result = delaunay_2d_calc(input, CDT_INSIDE_WITH_HOLES); - strokes_triangles[group_id].resize(result.face.size()); - MutableSpan r_tris = strokes_triangles[group_id]; + strokes_triangles[shape_index].resize(result.face.size()); + MutableSpan r_tris = strokes_triangles[shape_index]; threading::parallel_for(result.face.index_range(), 512, [&](const IndexRange range) { for (const int i : range) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc index 7d7c3e29158..2893d9952b4 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc +++ b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc @@ -725,24 +725,24 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); - const Vector groups = info.drawing.get_shapes_index_masks(memory); + const Vector shapes = info.drawing.shapes(memory); /* Precompute all the triangle and vertex counts. * In case the drawing should not be rendered, we need to compute the offset where the next * drawing begins. */ - Array num_triangles_per_stroke(groups.size()); + Array num_triangles_per_stroke(shapes.size()); Array num_vertices_per_stroke(visible_strokes.size()); int total_num_triangles = 0; int total_num_vertices = 0; int current_curve = 0; - for (const int group_id : groups.index_range()) { - const IndexMask &group = groups[group_id]; + for (const int shape_index : shapes.index_range()) { + const IndexMask &shape = shapes[shape_index]; - const int num_stroke_triangles = triangles[group_id].size(); - num_triangles_per_stroke[group_id] = num_stroke_triangles; + const int num_stroke_triangles = triangles[shape_index].size(); + num_triangles_per_stroke[shape_index] = num_stroke_triangles; total_num_triangles += num_stroke_triangles; - group.foreach_index([&](const int curve_i) { + shape.foreach_index([&](const int curve_i) { const IndexRange points = points_by_curve[curve_i]; const int num_stroke_vertices = (points.size() + int(cyclic[curve_i] && (points.size() >= 3))); @@ -798,10 +798,10 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData const bool is_onion = info.onion_id != 0; current_curve = 0; - for (const int group_id : groups.index_range()) { - const IndexMask &group = groups[group_id]; + for (const int shape_index : shapes.index_range()) { + const IndexMask &shape = shapes[shape_index]; - const int curve_i = group.first(); + const int curve_i = shape.first(); /* The material index is allowed to be negative as it's stored as a generic attribute. We * clamp it here to avoid crashing in the rendering code. Any stroke with a material < 0 @@ -811,7 +811,7 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; const bool show_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0); - const bool show_fill = (!triangles[group_id].is_empty()) && + const bool show_fill = (!triangles[shape_index].is_empty()) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0) && (!pd->simplify_fill); const bool hide_onion = is_onion && ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0 || @@ -820,11 +820,11 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData (only_lines && !is_onion) || hide_onion; if (skip_stroke) { - t_offset += num_triangles_per_stroke[group_id]; - for (const int i : group.index_range()) { + t_offset += num_triangles_per_stroke[shape_index]; + for (const int i : shape.index_range()) { t_offset += num_vertices_per_stroke[current_curve + i] * 2; }; - current_curve += group.size(); + current_curve += shape.size(); continue; } @@ -870,13 +870,13 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData if (show_fill) { const int v_first = t_offset * 3; - const int v_count = num_triangles_per_stroke[group_id] * 3; + const int v_count = num_triangles_per_stroke[shape_index] * 3; drawcall_add(geom, v_first, v_count); } - t_offset += num_triangles_per_stroke[group_id]; + t_offset += num_triangles_per_stroke[shape_index]; - group.foreach_index([&](const int curve_i) { + shape.foreach_index([&](const int curve_i) { const IndexRange points = points_by_curve[curve_i]; if (show_stroke) { diff --git a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh index 2d247884e74..fa5b401ff31 100644 --- a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh +++ b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh @@ -89,21 +89,21 @@ class GreasePencil { IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); - const Vector groups = info.drawing.get_shapes_index_masks(memory); + const Vector shapes = info.drawing.shapes(memory); const Span> triangles = info.drawing.triangles(); const bool hide_onion = info.onion_id != 0; - for (const int group_id : groups.index_range()) { - const IndexMask &group = groups[group_id]; + for (const int shape_index : shapes.index_range()) { + const IndexMask &shape = shapes[shape_index]; - const int material_index = stroke_materials[group.first()]; + const int material_index = stroke_materials[shape.first()]; MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1); const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; - const int num_stroke_triangles = triangles[group_id].size(); + const int num_stroke_triangles = triangles[shape_index].size(); if (hide_material || hide_onion) { t_offset += num_stroke_triangles; @@ -123,7 +123,7 @@ class GreasePencil { t_offset += num_stroke_triangles; - group.foreach_index([&](const int curve_i) { + shape.foreach_index([&](const int curve_i) { const IndexRange points = points_by_curve[curve_i]; const int num_stroke_vertices = (points.size() + diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc index 6caeb6a57ee..5b5f4d1b65b 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.cc +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -323,20 +323,20 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( *ob, info.drawing, memory); - const Vector groups = info.drawing.get_shapes_index_masks(memory); + const Vector shapes = info.drawing.shapes(memory); const Span> triangles = info.drawing.triangles(); - for (const int group_id : groups.index_range()) { - const IndexMask &group = groups[group_id]; + for (const int shape_index : shapes.index_range()) { + const IndexMask &shape = shapes[shape_index]; - const int material_index = stroke_materials[group.first()]; + const int material_index = stroke_materials[shape.first()]; MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1); const bool hide_onion = info.onion_id != 0; const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; - const int num_stroke_triangles = triangles[group_id].size(); + const int num_stroke_triangles = triangles[shape_index].size(); const bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; const bool show_fill = (num_stroke_triangles != 0) && @@ -352,7 +352,7 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, t_offset += num_stroke_triangles; - group.foreach_index([&](const int curve_i) { + shape.foreach_index([&](const int curve_i) { const IndexRange points = points_by_curve[curve_i]; const int num_stroke_vertices = (points.size() + int(cyclic[curve_i] && (points.size() >= 3))); diff --git a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc index a569167f78f..66f33d329cb 100644 --- a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc +++ b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc @@ -1194,7 +1194,7 @@ static void grease_pencil_geom_batch_ensure(Object &object, GPU_indexbuf_add_tri_verts(&ibo, v_mat + 2, v_mat + 1, v_mat + 3); }; - const Vector groups = info.drawing.get_shapes_index_masks(memory); + const Vector shapes = info.drawing.shapes(memory); const Array point_to_curve_map = curves.point_to_curve_map(); auto point_to_id = [&](uint32_t p) { @@ -1203,9 +1203,9 @@ static void grease_pencil_geom_batch_ensure(Object &object, return (1 + (p - points_.first()) + verts_start_offsets[curve_]) << GP_VERTEX_ID_SHIFT; }; - for (const int group_id : groups.index_range()) { - const IndexMask &group = groups[group_id]; - const Span tris_slice = triangles[group_id]; + for (const int shape_index : shapes.index_range()) { + const IndexMask &shape = shapes[shape_index]; + const Span tris_slice = triangles[shape_index]; /* Add the triangle indices to the index buffer. */ for (const uint3 tri : tris_slice) { @@ -1213,10 +1213,10 @@ static void grease_pencil_geom_batch_ensure(Object &object, GPU_indexbuf_add_tri_verts(&ibo, tri_verts.x, tri_verts.y, tri_verts.z); } - const float4x2 texture_matrix = texture_matrices[group.first()] * + const float4x2 texture_matrix = texture_matrices[shape.first()] * object_space_to_layer_space; - group.foreach_index([&](const int curve_i) { + shape.foreach_index([&](const int curve_i) { const IndexRange points = points_by_curve[curve_i]; const bool is_cyclic = cyclic[curve_i] && (points.size() > 2); const int verts_start_offset = verts_start_offsets[curve_i]; -- 2.30.2 From 674df0b9d8c63684c5da4b326b48f9c90f31a041 Mon Sep 17 00:00:00 2001 From: Casey Bianco-Davis Date: Sun, 1 Sep 2024 11:36:37 -0700 Subject: [PATCH 7/7] Cleanup: Rework offsets. --- .../intern/draw_cache_impl_grease_pencil.cc | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc index 66f33d329cb..9439483c716 100644 --- a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc +++ b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc @@ -1038,10 +1038,9 @@ static void grease_pencil_geom_batch_ensure(Object &object, ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, true); /* First, count how many vertices and triangles are needed for the whole object. Also record the - * offsets into the curves for the vertices and triangles. */ + * offsets into the curves for the vertices. */ int total_verts_num = 0; int total_triangles_num = 0; - int v_offset = 0; Vector> verts_start_offsets_per_visible_drawing; for (const ed::greasepencil::DrawingInfo &info : drawings) { const bke::CurvesGeometry &curves = info.drawing.strokes(); @@ -1050,35 +1049,37 @@ static void grease_pencil_geom_batch_ensure(Object &object, IndexMaskMemory memory; const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( object, info.drawing, memory); + const Span> triangles = info.drawing.triangles(); + const Vector shapes = info.drawing.shapes(memory); - const int num_curves = visible_strokes.size(); - const int verts_start_offsets_size = num_curves; - Array verts_start_offsets(verts_start_offsets_size); + Array verts_start_offsets(curves.curves_num(), 0); /* Calculate the vertex offsets for all the visible curves. */ int num_cyclic = 0; int num_points = 0; - visible_strokes.foreach_index([&](const int curve_i, const int pos) { - IndexRange points = points_by_curve[curve_i]; - const bool is_cyclic = cyclic[curve_i] && (points.size() > 2); + for (const int shape_index : shapes.index_range()) { + const IndexMask &shape = shapes[shape_index]; - if (is_cyclic) { - num_cyclic++; - } + total_triangles_num += triangles[shape_index].size(); - verts_start_offsets[pos] = v_offset; - v_offset += 1 + points.size() + (is_cyclic ? 1 : 0) + 1; - num_points += points.size(); - }); + shape.foreach_index([&](const int curve_i) { + IndexRange points = points_by_curve[curve_i]; + const bool is_cyclic = cyclic[curve_i] && (points.size() > 2); - /* One vertex is stored before and after as padding. Cyclic strokes have one extra vertex. */ - total_verts_num += num_points + num_cyclic + num_curves * 2; - total_triangles_num += (num_points + num_cyclic) * 2; + if (is_cyclic) { + num_cyclic++; + } - for (const int group_id : info.drawing.triangles().index_range()) { - total_triangles_num += info.drawing.triangles()[group_id].size(); + verts_start_offsets[curve_i] = total_verts_num; + /* One vertex is stored before and after as padding. Cyclic strokes have one extra vertex. + */ + total_verts_num += 1 + points.size() + (is_cyclic ? 1 : 0) + 1; + num_points += points.size(); + }); } + total_triangles_num += (num_points + num_cyclic) * 2; + verts_start_offsets_per_visible_drawing.append(std::move(verts_start_offsets)); } -- 2.30.2