[Bf-blender-cvs] [57cee583c4f] temp-T101739-fix-seam-bleeding-non-manifold: Improved performance by allocating a single array and use RowViews.

Jeroen Bakker noreply at git.blender.org
Thu Jan 19 11:36:38 CET 2023


Commit: 57cee583c4f61eae5a94a84fa4032392c365c5e8
Author: Jeroen Bakker
Date:   Thu Jan 19 11:36:31 2023 +0100
Branches: temp-T101739-fix-seam-bleeding-non-manifold
https://developer.blender.org/rB57cee583c4f61eae5a94a84fa4032392c365c5e8

Improved performance by allocating a single array and use RowViews.

===================================================================

M	source/blender/blenkernel/intern/pbvh_pixels_copy.cc

===================================================================

diff --git a/source/blender/blenkernel/intern/pbvh_pixels_copy.cc b/source/blender/blenkernel/intern/pbvh_pixels_copy.cc
index 7123f806268..5aaf48c4883 100644
--- a/source/blender/blenkernel/intern/pbvh_pixels_copy.cc
+++ b/source/blender/blenkernel/intern/pbvh_pixels_copy.cc
@@ -23,6 +23,8 @@
 
 namespace blender::bke::pbvh::pixels {
 
+const int GRAIN_SIZE = 128;
+
 /** Coordinate space of a coordinate. */
 enum class CoordSpace {
   /**
@@ -225,96 +227,52 @@ class PixelNodesTileData : public Vector<std::reference_wrapper<UDIMTilePixels>>
  */
 
 struct Rows {
-  struct Row {
-    enum class PixelType {
-      Undecided,
-      /** This pixel is directly affected by a brush and doesn't need to be solved. */
-      Brush,
-      Selected,
-      /** This pixel will be copid from another pixel to solve non-manifold edge bleeding. */
-      CopyFromClosestEdge,
-    };
-
-    struct Pixel {
-      PixelType type = PixelType::Undecided;
-      float distance = std::numeric_limits<float>::max();
-      CopyPixelCommand copy_command;
-      /**
-       * Index of the edge in the list of non-manifold edges.
-       *
-       * The edge is kept to calculate athe mix factor between the two pixels that have chosen to
-       * be mixed.
-       */
-      int64_t edge_index = -1;
-
-      Pixel() = default;
-
-      Pixel(int2 coordinate)
-      {
-        copy_command.destination = coordinate;
-        copy_command.source_1 = coordinate;
-        copy_command.source_2 = coordinate;
-        copy_command.mix_factor = 0.0f;
-      }
-    };
-
-    int row_number = 0;
-    Array<Pixel> pixels;
-    Row() = delete;
-    Row(int64_t width) : pixels(width)
-    {
-    }
-
-    void reinit(int y)
-    {
-      row_number = y;
-      for (int x = 0; x < pixels.size(); x++) {
-        pixels[x] = Pixel(int2(x, y));
-      }
-    }
+  enum class PixelType {
+    Undecided,
+    /** This pixel is directly affected by a brush and doesn't need to be solved. */
+    Brush,
+    Selected,
+    /** This pixel will be copid from another pixel to solve non-manifold edge bleeding. */
+    CopyFromClosestEdge,
+  };
 
+  struct Pixel {
+    PixelType type = PixelType::Undecided;
+    float distance = std::numeric_limits<float>::max();
+    CopyPixelCommand copy_command;
     /**
-     * Mark pixels that needs to be evaluated. Pixels that are marked will have its `edge_index`
-     * filled.
+     * Index of the edge in the list of non-manifold edges.
+     *
+     * The edge is kept to calculate athe mix factor between the two pixels that have chosen to
+     * be mixed.
      */
-    void mark_for_evaluation(const Rows &rows, const NonManifoldTileEdges &tile_edges)
-    {
-      for (int tile_edge_index : tile_edges.index_range()) {
-        const Edge<CoordSpace::Tile> &tile_edge = tile_edges[tile_edge_index];
-        rcti edge_bounds = get_bounds(tile_edge);
-        add_margin(edge_bounds, rows.margin);
-        clamp(edge_bounds, rows.resolution);
+    int64_t edge_index = -1;
 
-        if (edge_bounds.ymax < row_number) {
-          continue;
-        }
-        if (edge_bounds.ymin > row_number) {
-          continue;
-        }
+    Pixel() = default;
 
-        for (const int x : IndexRange(edge_bounds.xmin, BLI_rcti_size_x(&edge_bounds))) {
-          Pixel &pixel = pixels[x];
-          if (pixel.type == PixelType::Brush) {
-            continue;
-          }
-          BLI_assert_msg(pixel.type != PixelType::CopyFromClosestEdge,
-                         "PixelType::CopyFromClosestEdge isn't allowed to be set as it is set "
-                         "when finding the pixels to copy.");
+    Pixel(int2 coordinate)
+    {
+      copy_command.destination = coordinate;
+      copy_command.source_1 = coordinate;
+      copy_command.source_2 = coordinate;
+      copy_command.mix_factor = 0.0f;
+    }
+  };
 
-          const float2 point(pixel.copy_command.destination);
-          float2 closest_edge_point;
-          closest_to_line_segment_v2(closest_edge_point,
-                                     point,
-                                     tile_edge.vertex_1.coordinate,
-                                     tile_edge.vertex_2.coordinate);
-          float distance_to_edge = blender::math::distance(closest_edge_point, point);
-          if (distance_to_edge < rows.margin && distance_to_edge < pixel.distance) {
-            pixel.type = PixelType::Selected;
-            pixel.distance = distance_to_edge;
-            pixel.edge_index = tile_edge_index;
-          }
-        }
-      }
+  int2 resolution;
+  int margin;
+  Array<Pixel> pixels;
+
+  struct RowView {
+    int row_number = 0;
+    /** Not owning pointer into Row.pixels starts at the start of the row.*/
+    MutableSpan<Pixel> pixels;
+    RowView() = delete;
+    RowView(Rows &rows, int64_t row_number)
+        : row_number(row_number),
+          pixels(
+              MutableSpan<Pixel>(&rows.pixels[row_number * rows.resolution.x], rows.resolution.x))
+    {
     }
 
     /**
@@ -346,7 +304,8 @@ struct Rows {
           if (source == first_source) {
             continue;
           }
-          if (rows.rows[sy].pixels[sx].type != PixelType::Brush) {
+          int pixel_index = sy * rows.resolution.y + sx;
+          if (rows.pixels[pixel_index].type != PixelType::Brush) {
             continue;
           }
 
@@ -403,7 +362,7 @@ struct Rows {
         int2 found_source(0);
 
         for (int sy : IndexRange(bounds.ymin, BLI_rcti_size_y(&bounds))) {
-          Row &row = rows.rows[sy];
+          RowView row(rows, sy);
           for (int sx : IndexRange(bounds.xmin, BLI_rcti_size_x(&bounds))) {
             Pixel &source = row.pixels[sx];
             if (source.type != PixelType::Brush) {
@@ -521,23 +480,26 @@ struct Rows {
     }
   };
 
-  int2 resolution;
-  int margin;
-  Vector<Row> rows;
-
   Rows(int2 resolution, int margin, const PixelNodesTileData &node_tile_pixels)
-      : resolution(resolution), margin(margin)
+      : resolution(resolution), margin(margin), pixels(resolution.x * resolution.y)
   {
     TIMEIT_START(mark_brush);
-    Row row_template(resolution.x);
-    rows.resize(resolution.y, row_template);
-    for (int row_number : rows.index_range()) {
-      rows[row_number].reinit(row_number);
-    }
+    init_pixels();
     mark_pixels_effected_by_brush(node_tile_pixels);
     TIMEIT_END(mark_brush);
   }
 
+  void init_pixels()
+  {
+    for (int64_t y : IndexRange(resolution.y)) {
+      for (int64_t x : IndexRange(resolution.x)) {
+        int64_t index = y * resolution.y + x;
+        int2 position(x, y);
+        pixels[index] = Pixel(position);
+      }
+    }
+  }
+
   /**
    * Mark pixels that are painted on by the brush. Those pixels don't need to be updated, but will
    * act as a source for other pixels.
@@ -547,12 +509,12 @@ struct Rows {
     for (const UDIMTilePixels &tile_pixels : nodes_tile_pixels) {
       threading::parallel_for_each(
           tile_pixels.pixel_rows, [&](const PackedPixelRow &encoded_pixels) {
-            Row &row = rows[encoded_pixels.start_image_coordinate.y];
             for (int x = encoded_pixels.start_image_coordinate.x;
                  x < encoded_pixels.start_image_coordinate.x + encoded_pixels.num_pixels;
                  x++) {
-              row.pixels[x].type = Row::PixelType::Brush;
-              row.pixels[x].distance = 0.0f;
+              int64_t index = encoded_pixels.start_image_coordinate.y * resolution.x + x;
+              pixels[index].type = PixelType::Brush;
+              pixels[index].distance = 0.0f;
             }
           });
     }
@@ -560,18 +522,58 @@ struct Rows {
 
   void find_copy_source(const NonManifoldTileEdges &tile_edges)
   {
-    threading::parallel_for_each(rows, [&](Row &row) { row.find_copy_source(*this, tile_edges); });
+    threading::parallel_for(IndexRange(resolution.y), GRAIN_SIZE, [&](IndexRange range) {
+      for (int row_number : range) {
+        RowView row(*this, row_number);
+        row.find_copy_source(*this, tile_edges);
+      }
+    });
   }
 
+  /**
+   * Mark pixels that needs to be evaluated. Pixels that are marked will have its `edge_index`
+   * filled.
+   */
   void mark_for_evaluation(const NonManifoldTileEdges &tile_edges)
   {
-    threading::parallel_for_each(rows,
-                                 [&](Row &row) { row.mark_for_evaluation(*this, tile_edges); });
+    for (int tile_edge_index : tile_edges.index_range()) {
+      const Edge<CoordSpace::Tile> &tile_edge = tile_edges[tile_edge_index];
+      rcti edge_bounds = get_bounds(tile_edge);
+      add_margin(edge_bounds, margin);
+      clamp(edge_bounds, resolution);
+
+      for (const int64_t sy : IndexRange(edge_bounds.ymin, BLI_rcti_size_y(&edge_bounds))) {
+        for (const int64_t sx : IndexRange(edge_bounds.xmin, BLI_rcti_size_x(&edge_bounds))) {
+          const int64_t index = sy * resolution.x + sx;
+          Pixel &pixel = pixels[index];
+          if (pixel.type == PixelType::Brush) {
+            continue;
+          }
+          BLI_assert_msg(pixel.type != PixelType::CopyFromClosestEdge,
+                         "PixelType::CopyFromClosestEdge isn't allowed to be set as it is set "
+                         "when finding the pixels to copy.");
+
+          const float2 point(sx, sy);
+          float2 closest_edge_point;
+          closest_to_line_segment_v2(closest_edge_point,
+                                     point,
+                                     tile_edge.vertex_1.coordinate,
+                                     tile_edge.vertex_2.coordinate);
+          float distance_to_edge = blender::math::distance(closest_edge_point, point);
+          if (distance_to_edge < margin && distance_to_edge < pixel.distance) {
+            pixel.type = PixelType::Selected;
+            pixel.distance = distance_to_edge;
+            pixel.edge_index = tile_edge_index;
+          }
+        }
+      }
+    }
   }
 
-  void pack_into(CopyPixelTile &copy_tile) const
+  void pack_into(CopyPixelTile &copy_tile)
   {
-    for (const Row &row : rows) {
+    for (int row_number : IndexRange(resolution.y)) {
+      RowView row(*this, row_number);
       row.pack_into(copy_tile);
     }
  

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list