Ignore insert/erase function during PreRender's itemsDirtyRects 12/271512/2
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 22 Feb 2022 08:19:22 +0000 (17:19 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Tue, 22 Feb 2022 09:08:52 +0000 (18:08 +0900)
Previous code just insert and erase when the renderer hold dirtyRect
more than 3.
Each insert & erase operation in std::vector cost O(N). and it is expensive.

This patch reduce the insert & erase operation when renderer hold dirtyRect
more than 3. We can do tge same job by just moving data linearly.

(This patch is follow up 250728)

Change-Id: I230f32f07c72c3a4f15c6bb7f6a42bd61ce87d1d
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/render/common/render-manager.cpp

index bb35b69..084db0e 100644 (file)
@@ -95,6 +95,12 @@ inline Graphics::Rect2D RecalculateScissorArea(Graphics::Rect2D scissorArea, int
   }
   return newScissorArea;
 }
+
+/**
+ * @brief The number of dirty rects per renderer in itemDirtyRects list.
+ * If this value is 3, keep only last 3 dirty rects for the same node and renderer.
+ */
+constexpr int MAX_DIRTY_RECT_PER_RENDERER = 3;
 } // namespace
 /**
  * Structure to contain internal data
@@ -624,15 +630,16 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>&
                   rect.height      = ((bottom + 16) / 16) * 16 - rect.y;
 
                   // Found valid dirty rect.
-                  // 1. Insert it in the sorted array of the dirty rects.
-                  // 2. Mark the related dirty rects as visited so they will not be removed below.
-                  // 3. Keep only last 3 dirty rects for the same node and renderer (Tizen uses 3 back buffers, Ubuntu 1).
+                  // 1. Mark the related dirty rects as visited so they will not be removed below.
+                  // 2. Keep only last "MAX_DIRTY_RECT_PER_RENDERER" dirty rects for the same node and renderer (Tizen uses 3 back buffers, Ubuntu 1).
+                  // 3-1. If itemDirtyRect hold MAX_DIRTY_RECT_PER_RENDERER rects, remove oldest one and insert it in the sorted array of the dirty rects.
+                  // 3-2. Else, Insert it in the sorted array of the dirty rects.
                   dirtyRect.rect    = rect;
                   auto dirtyRectPos = std::lower_bound(itemsDirtyRects.begin(), itemsDirtyRects.end(), dirtyRect);
-                  dirtyRectPos      = itemsDirtyRects.insert(dirtyRectPos, dirtyRect);
 
-                  int c = 1;
-                  while(++dirtyRectPos != itemsDirtyRects.end())
+                  auto originDirtyRectPos = dirtyRectPos;
+                  bool hasMaxDirtyRect    = false;
+                  while(dirtyRectPos != itemsDirtyRects.end())
                   {
                     if(dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer)
                     {
@@ -640,17 +647,36 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector<Rect<int>>&
                     }
 
                     dirtyRectPos->visited = true;
-                    Rect<int>& dirtRect   = dirtyRectPos->rect;
-                    rect.Merge(dirtRect);
+                    rect.Merge(dirtyRectPos->rect);
 
-                    c++;
-                    if(c > 3) // no more then 3 previous rects
+                    ++dirtyRectPos;
+
+                    if((dirtyRectPos - originDirtyRectPos) == MAX_DIRTY_RECT_PER_RENDERER) // no more than MAX_DIRTY_RECT_PER_RENDERER previous rects
                     {
-                      itemsDirtyRects.erase(dirtyRectPos);
+                      hasMaxDirtyRect = true;
                       break;
                     }
                   }
 
+                  if(hasMaxDirtyRect)
+                  {
+                    // If we have already MAX_DIRTY_RECT_PER_RENDERER for the same item, just copy it.
+                    // Remove the oldest rect (at pos + MAX_DIRTY_RECT_PER_RENDERER - 1)
+                    // and move other rects one step.
+                    // and insert new dirtyRect at originDirtyRectPos.
+                    auto pos = originDirtyRectPos - itemsDirtyRects.begin();
+                    for(auto i = MAX_DIRTY_RECT_PER_RENDERER - 1; i > 0; i--)
+                    {
+                      itemsDirtyRects[pos + i] = itemsDirtyRects[pos + i - 1];
+                    }
+                    itemsDirtyRects[pos] = dirtyRect;
+                  }
+                  else
+                  {
+                    // Else, just insert the new dirtyrect in the correct position
+                    itemsDirtyRects.insert(originDirtyRectPos, dirtyRect);
+                  }
+
                   damagedRects.push_back(rect);
                 }
               }