[Bf-blender-cvs] [01dcca4283f] gpencil-new-data-proposal: Change sorting of frames in frame array

Falk David noreply at git.blender.org
Mon Nov 28 23:41:25 CET 2022


Commit: 01dcca4283f575d7d687f200fdd98f578cd51f07
Author: Falk David
Date:   Mon Nov 28 23:40:22 2022 +0100
Branches: gpencil-new-data-proposal
https://developer.blender.org/rB01dcca4283f575d7d687f200fdd98f578cd51f07

Change sorting of frames in frame array

This change makes it so that frames are sorted by the
layer index first, then by the frame number.
The benefit is that we can return an `IndexRange` now
when getting all the frames on one layer.

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

M	source/blender/blenkernel/intern/gpencil_new_proposal.cc
M	source/blender/blenkernel/intern/gpencil_new_proposal.hh
M	source/blender/blenkernel/intern/gpencil_new_proposal_test.cc

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

diff --git a/source/blender/blenkernel/intern/gpencil_new_proposal.cc b/source/blender/blenkernel/intern/gpencil_new_proposal.cc
index bf9911b3638..e543fa7d47b 100644
--- a/source/blender/blenkernel/intern/gpencil_new_proposal.cc
+++ b/source/blender/blenkernel/intern/gpencil_new_proposal.cc
@@ -49,12 +49,6 @@ IndexMask GPLayerGroup::layers_index_mask()
   return {reinterpret_cast<int64_t>(this->layer_indices), this->layer_indices_size};
 }
 
-/* GPDataRuntime */
-IndexMask GPDataRuntime::frame_index_masks_cache_for_layer(int layer_index)
-{
-  return frame_index_masks_cache.lookup(layer_index).as_span();
-}
-
 /* GPStroke */
 Span<float3> GPStroke::points_positions() const
 {
@@ -140,15 +134,18 @@ GPFrame::~GPFrame()
 
 bool GPFrame::operator<(const GPFrameKey key) const
 {
-  if (this->start_time == key.start_time) {
-    return this->layer_index < key.layer_index;
+  if (this->layer_index == key.layer_index) {
+    return this->start_time < key.start_time;
   }
-  return this->start_time < key.start_time;
+  return this->layer_index < key.layer_index;
 }
 
 bool GPFrame::operator<(const GPFrame &other) const
 {
-  return *this < other.get_frame_key();
+  if (this->layer_index == other.layer_index) {
+    return this->start_time < other.start_time;
+  }
+  return this->layer_index < other.layer_index;
 }
 
 bool GPFrame::operator==(const GPFrame &other) const
@@ -316,44 +313,54 @@ GPFrame &GPData::frames_for_write(int index)
   return this->frames_for_write()[index];
 }
 
-IndexMask GPData::frames_on_layer(int layer_index) const
+IndexRange GPData::frames_on_layer(int layer_index) const
 {
   if (layer_index < 0 || layer_index > this->layers_size) {
-    return IndexMask();
+    return {};
   }
 
   /* If the indices are cached for this layer, use the cache. */
-  if (this->runtime->frame_index_masks_cache.contains(layer_index)) {
-    return this->runtime->frame_index_masks_cache_for_layer(layer_index);
+  if (this->runtime->frames_index_range_cache.contains(layer_index)) {
+    return this->runtime->frames_index_range_cache_for_layer(layer_index);
   }
 
   /* A double checked lock. */
-  std::scoped_lock{this->runtime->frame_index_masks_cache_mutex};
-  if (this->runtime->frame_index_masks_cache.contains(layer_index)) {
-    return this->runtime->frame_index_masks_cache_for_layer(layer_index);
-  }
-
-  Vector<int64_t> indices;
-  const IndexMask mask = index_mask_ops::find_indices_based_on_predicate(
-      IndexMask(this->frames_size), 1024, indices, [&](const int index) {
-        return this->frames()[index].layer_index == layer_index;
-      });
+  std::scoped_lock{this->runtime->frames_index_range_cache_mutex};
+  if (this->runtime->frames_index_range_cache.contains(layer_index)) {
+    return this->runtime->frames_index_range_cache_for_layer(layer_index);
+  }
+
+  auto it_lower = std::lower_bound(
+      this->frames().begin(),
+      this->frames().end(),
+      layer_index,
+      [](const GPFrame &frame, const int index) { return frame.layer_index < index; });
+  auto it_upper = std::upper_bound(
+      this->frames().begin(),
+      this->frames().end(),
+      layer_index,
+      [](const int index, const GPFrame &frame) { return frame.layer_index < index; });
+
+  /* Get the index of the first frame. */
+  int start_idx = std::distance(this->frames().begin(), it_lower);
+  /* Calculate size of the layer. */
+  int frames_size = std::distance(it_lower, it_upper);
 
   /* Cache the resulting index mask. */
-  this->runtime->frame_index_masks_cache.add(layer_index, std::move(indices));
-  return mask;
+  this->runtime->frames_index_range_cache.add(layer_index, {start_idx, frames_size});
+  return {start_idx, frames_size};
 }
 
-IndexMask GPData::frames_on_layer(GPLayer &layer) const
+IndexRange GPData::frames_on_layer(GPLayer &layer) const
 {
   int index = this->layers().first_index_try(layer);
   if (index == -1) {
-    return IndexMask();
+    return {};
   }
   return frames_on_layer(index);
 }
 
-IndexMask GPData::frames_on_active_layer() const
+IndexRange GPData::frames_on_active_layer() const
 {
   return frames_on_layer(this->active_layer_index);
 }
@@ -625,11 +632,11 @@ int GPData::add_frame_on_layer_initialized(int layer_index, int frame_start, int
 
 void GPData::update_frames_array()
 {
-  /* Make sure frames are ordered chronologically and by layer order. */
+  /* Make sure frames are ordered by layers and chronologically. */
   std::sort(this->frames_for_write().begin(), this->frames_for_write().end());
 
-  /* Clear the cached indices since they are (probably) no longer valid. */
-  this->runtime->frame_index_masks_cache.clear();
+  /* Clear the cached reanges since they are (probably) no longer valid. */
+  this->runtime->frames_index_range_cache.clear();
 }
 
 }  // namespace blender::bke
\ No newline at end of file
diff --git a/source/blender/blenkernel/intern/gpencil_new_proposal.hh b/source/blender/blenkernel/intern/gpencil_new_proposal.hh
index ed859e83ad9..94935c8afef 100644
--- a/source/blender/blenkernel/intern/gpencil_new_proposal.hh
+++ b/source/blender/blenkernel/intern/gpencil_new_proposal.hh
@@ -101,8 +101,13 @@ typedef struct GPFrame {
 
 typedef struct GPData {
   /**
-   * The array of grease pencil frames. This is kept in chronological order (tiebreaks for two
-   * frames on different layers are resloved by the order of the layers).
+   * The array of grease pencil frames.
+   *
+   * The array is always assumed to be sorted. First by the layer index of each frame, then in
+   * chronological order, like so:
+   *
+   *  `[ frame 1 on layer 1, frame 2 on layer 1, frame 3 on layer 1, ...
+   *     frame 1 on layer 2, frame 2 on layer 2, frame 3 on layer 2, ...]`
    */
   GPFrame *frames_array;
   int frames_size;
@@ -175,12 +180,15 @@ class GPDataRuntime {
   /* mutable void *sbuffer */
 
   /**
-   * Cache that maps the index of a layer to the index mask of the frames in that layer.
+   * Cache that maps the index of a layer to the index range of the frames in that layer.
    */
-  mutable Map<int, Vector<int64_t>> frame_index_masks_cache;
-  mutable std::mutex frame_index_masks_cache_mutex;
+  mutable Map<int, IndexRange> frames_index_range_cache;
+  mutable std::mutex frames_index_range_cache_mutex;
 
-  IndexMask frame_index_masks_cache_for_layer(int layer_index);
+  IndexRange frames_index_range_cache_for_layer(int layer_index)
+  {
+    return frames_index_range_cache.lookup(layer_index);
+  };
 };
 
 /**
@@ -297,9 +305,9 @@ class GPData : public ::GPData {
   MutableSpan<GPFrame> frames_for_write();
   GPFrame &frames_for_write(int index);
 
-  IndexMask frames_on_layer(int layer_index) const;
-  IndexMask frames_on_layer(GPLayer &layer) const;
-  IndexMask frames_on_active_layer() const;
+  IndexRange frames_on_layer(int layer_index) const;
+  IndexRange frames_on_layer(GPLayer &layer) const;
+  IndexRange frames_on_active_layer() const;
 
   Span<GPLayer> layers() const;
   const GPLayer &layers(int index) const;
diff --git a/source/blender/blenkernel/intern/gpencil_new_proposal_test.cc b/source/blender/blenkernel/intern/gpencil_new_proposal_test.cc
index 34ac95fbedb..026f3cf1f9e 100644
--- a/source/blender/blenkernel/intern/gpencil_new_proposal_test.cc
+++ b/source/blender/blenkernel/intern/gpencil_new_proposal_test.cc
@@ -222,7 +222,7 @@ TEST(gpencil_proposal, CheckFramesSorted2)
   const int frame_numbers_layer1[5] = {10, 5, 6, 1, 3};
   const int frame_numbers_layer2[5] = {8, 5, 7, 1, 4};
   const int frame_numbers_sorted2[10][2] = {
-      {0, 1}, {1, 1}, {0, 3}, {1, 4}, {0, 5}, {1, 5}, {0, 6}, {1, 7}, {1, 8}, {0, 10}};
+      {0, 1}, {0, 3}, {0, 5}, {0, 6}, {0, 10}, {1, 1}, {1, 4}, {1, 5}, {1, 7}, {1, 8}};
 
   const int layer1_index = data.add_layer("TestLayer1");
   const int layer2_index = data.add_layer("TestLayer2");
@@ -244,8 +244,7 @@ TEST(gpencil_proposal, IterateOverFramesOnLayer)
   const int frame_numbers_layer1[5] = {10, 5, 6, 1, 3};
   const int frame_numbers_layer2[5] = {8, 5, 7, 1, 4};
 
-  const int frame_numbers_sorted1[5] = {1, 3, 5, 6, 10};
-  const int frame_numbers_sorted2[5] = {1, 4, 5, 7, 8};
+  const int frame_numbers_sorted[10] = {1, 3, 5, 6, 10, 1, 4, 5, 7, 8};
 
   const int layer1_index = data.add_layer("TestLayer1");
   const int layer2_index = data.add_layer("TestLayer2");
@@ -254,16 +253,16 @@ TEST(gpencil_proposal, IterateOverFramesOnLayer)
     data.add_frame_on_layer(layer2_index, frame_numbers_layer2[i]);
   }
 
-  IndexMask indices_frames_layer1 = data.frames_on_layer(layer1_index);
-  EXPECT_TRUE(data.runtime->frame_index_masks_cache.contains(layer1_index));
-  for (const int i : indices_frames_layer1.index_range()) {
-    EXPECT_EQ(data.frames(indices_frames_layer1[i]).start_time, frame_numbers_sorted1[i]);
+  data.frames_on_layer(layer1_index);
+  EXPECT_TRUE(data.runtime->frames_index_range_cache.contains(layer1_index));
+  for (const int i : data.frames_on_layer(layer1_index)) {
+    EXPECT_EQ(data.frames(i).start_time, frame_numbers_sorted[i]);
   }
 
-  IndexMask indices_frames_layer2 = data.frames_on_layer(layer2_index);
-  EXPECT_TRUE(data.runtime->frame_index_masks_cache.contains(layer2_index));
-  for (const int i : indices_frames_layer2.index_range()) {
-    EXPECT_EQ(data.frames(indices_frames_layer2[i]).start_time, frame_numbers_sorted2[i]);
+  data.frames_on_layer(layer2_index);
+  EXPECT_TRUE(data.runtime->frames_index_range_cache.contains(layer2_index));
+  for (const int i : data.frames_on_layer(layer2_index)) {
+    EXPECT_EQ(data.frames(i).start_time, frame_numbers_sorted[i]);
   }
 }
 
@@ -387,8 +386,7 @@ TEST(gpencil_proposal, TimeMultiFrameTransformStrokes)
   float4x4 translate_mat = float4x4::from_location({1.0f, 2.0f, 3.0f});
   {
     SCOPED_TIMER("TimeMultiFrameTransformStrokes");
-    IndexMask indices_frames = data.frames_on_active_layer();
-    for (const int i : indices_frames) {
+    for (const int i : data.frames_on_active_layer()) {
       GPFrame &gpf = data.frames_for_write(i);
       Vector<GPStroke> gpf_strokes = gpf.strokes_for_write();
       MutableSpan<GPStroke> strokes_span = gpf_strokes.as_mutable_span();



More information about the Bf-blender-cvs mailing list