[gimp/gimp-2-10] app: in GimpProjection, fix reinit. of current row when chunk height changes



commit 61a181933c1b002476d79a23c383b8c02dc2da9d
Author: Ell <ell_se yahoo com>
Date:   Thu Dec 6 08:44:23 2018 -0500

    app: in GimpProjection, fix reinit. of current row when chunk height changes
    
    In GimpProjection's chunk renderer, when the chunk height changes
    in the middle of a row, we need to merge the remainder of the
    current render area back into the renderer's update region, and
    refetch the remainder of the row as the new render area, so that we
    don't miss any unrendered area, or re-render already-rendered area,
    due to the change in chunk height.  However, we should previously
    fail to verify that the fetched area is, in fact, the remainder of
    the current row, which could cause us to render the wrong area,
    missing parts of the update region.
    
    Fix this, by breaking up some of the chunk-renderer fucntions into
    smaller sub-functions, and using those in order to explicitly set
    the new render area to the remainder of the current row when the
    chunk height changes.  This also avoids erroneously merging the
    unflushed update region of the projection into the renderer's
    update region.
    
    (cherry picked from commit c9c2397b0d384717187870bad95373aff065cf39)

 app/core/gimpprojection.c | 132 ++++++++++++++++++++++++++++++----------------
 1 file changed, 87 insertions(+), 45 deletions(-)
---
diff --git a/app/core/gimpprojection.c b/app/core/gimpprojection.c
index 58762dcba1..b7b2c26a3d 100644
--- a/app/core/gimpprojection.c
+++ b/app/core/gimpprojection.c
@@ -185,11 +185,16 @@ static void        gimp_projection_chunk_render_start    (GimpProjection  *proj)
 static void        gimp_projection_chunk_render_stop     (GimpProjection  *proj);
 static gboolean    gimp_projection_chunk_render_callback (gpointer         data);
 static void        gimp_projection_chunk_render_init     (GimpProjection  *proj);
-static void        gimp_projection_chunk_render_reinit   (GimpProjection  *proj,
-                                                          gboolean         assume_running);
+static void        gimp_projection_chunk_render_reinit   (GimpProjection  *proj);
+static void        gimp_projection_chunk_render_merge    (GimpProjection  *proj);
 static gboolean    gimp_projection_chunk_render_iteration(GimpProjection  *proj,
                                                           gboolean         chunk);
 static gboolean    gimp_projection_chunk_render_next_area(GimpProjection  *proj);
+static void        gimp_projection_chunk_render_set_area (GimpProjection  *proj,
+                                                          gint             x,
+                                                          gint             y,
+                                                          gint             w,
+                                                          gint             h);
 static void        gimp_projection_paint_area            (GimpProjection  *proj,
                                                           gboolean         now,
                                                           gint             x,
@@ -605,7 +610,7 @@ gimp_projection_set_priority_rect (GimpProjection *proj,
       proj->priv->priority_rect = rect;
 
       if (proj->priv->chunk_render.idle_id)
-        gimp_projection_chunk_render_reinit (proj, FALSE);
+        gimp_projection_chunk_render_reinit (proj);
     }
 }
 
@@ -898,12 +903,11 @@ gimp_projection_chunk_render_init (GimpProjection *proj)
   chunk_render->target_n_pixels = GIMP_PROJECTION_CHUNK_WIDTH *
                                   GIMP_PROJECTION_CHUNK_HEIGHT;
 
-  gimp_projection_chunk_render_reinit (proj, FALSE);
+  gimp_projection_chunk_render_reinit (proj);
 }
 
 static void
-gimp_projection_chunk_render_reinit (GimpProjection *proj,
-                                     gboolean        assume_running)
+gimp_projection_chunk_render_reinit (GimpProjection *proj)
 {
   GimpProjectionChunkRender *chunk_render = &proj->priv->chunk_render;
 
@@ -929,38 +933,9 @@ gimp_projection_chunk_render_reinit (GimpProjection *proj,
    * its unrendered area with the update_areas list, and make it start
    * work on the next unrendered area in the list.
    */
-  if (chunk_render->idle_id || assume_running)
+  if (chunk_render->idle_id)
     {
-      cairo_rectangle_int_t rect;
-      gint                  work_h = 0;
-
-      if (chunk_render->work_x != chunk_render->x)
-        {
-          work_h = MIN (chunk_render->work_height,
-                        chunk_render->y + chunk_render->height -
-                        chunk_render->work_y);
-
-          rect.x      = chunk_render->work_x;
-          rect.y      = chunk_render->work_y;
-          rect.width  = chunk_render->x + chunk_render->width -
-                        chunk_render->work_x;
-          rect.height = work_h;
-
-          if (chunk_render->update_region)
-            cairo_region_union_rectangle (chunk_render->update_region, &rect);
-          else
-            chunk_render->update_region = cairo_region_create_rectangle (&rect);
-        }
-
-      rect.x      = chunk_render->x;
-      rect.y      = chunk_render->work_y + work_h;
-      rect.width  = chunk_render->width;
-      rect.height = chunk_render->y + chunk_render->height - rect.y;
-
-      if (chunk_render->update_region)
-        cairo_region_union_rectangle (chunk_render->update_region, &rect);
-      else
-        chunk_render->update_region = cairo_region_create_rectangle (&rect);
+      gimp_projection_chunk_render_merge (proj);
 
       gimp_projection_chunk_render_next_area (proj);
     }
@@ -982,6 +957,42 @@ gimp_projection_chunk_render_reinit (GimpProjection *proj,
     }
 }
 
+static void
+gimp_projection_chunk_render_merge (GimpProjection *proj)
+{
+  GimpProjectionChunkRender *chunk_render = &proj->priv->chunk_render;
+  cairo_rectangle_int_t      rect;
+  gint                       work_h = 0;
+
+  if (chunk_render->work_x != chunk_render->x)
+    {
+      work_h = MIN (chunk_render->work_height,
+                    chunk_render->y + chunk_render->height -
+                    chunk_render->work_y);
+
+      rect.x      = chunk_render->work_x;
+      rect.y      = chunk_render->work_y;
+      rect.width  = chunk_render->x + chunk_render->width -
+                    chunk_render->work_x;
+      rect.height = work_h;
+
+      if (chunk_render->update_region)
+        cairo_region_union_rectangle (chunk_render->update_region, &rect);
+      else
+        chunk_render->update_region = cairo_region_create_rectangle (&rect);
+    }
+
+  rect.x      = chunk_render->x;
+  rect.y      = chunk_render->work_y + work_h;
+  rect.width  = chunk_render->width;
+  rect.height = chunk_render->y + chunk_render->height - rect.y;
+
+  if (chunk_render->update_region)
+    cairo_region_union_rectangle (chunk_render->update_region, &rect);
+  else
+    chunk_render->update_region = cairo_region_create_rectangle (&rect);
+}
+
 /* Unless specified otherwise, projection re-rendering is organised by
  * ChunkRender, which amalgamates areas to be re-rendered and breaks
  * them into bite-sized chunks which are chewed on in an idle
@@ -1033,11 +1044,21 @@ gimp_projection_chunk_render_iteration (GimpProjection *proj,
 
   if (work_h != chunk_render->work_height)
     {
-      /* if the chunk height changed in the middle of a row, refetch the
-       * current area, so that we're back at the beginning of a row
+      /* if the chunk height changed in the middle of a row, merge the
+       * remaining area back into the update region, and reset the current area
+       * to the remainder of the row, using the new chunk height
        */
       if (work_x != chunk_render->x)
-        gimp_projection_chunk_render_reinit (proj, TRUE);
+        {
+          gimp_projection_chunk_render_merge (proj);
+
+          gimp_projection_chunk_render_set_area (
+            proj,
+            work_x,
+            work_y,
+            chunk_render->x + chunk_render->width - work_x,
+            work_h);
+        }
 
       chunk_render->work_height = work_h;
     }
@@ -1106,11 +1127,34 @@ gimp_projection_chunk_render_next_area (GimpProjection *proj)
 
   cairo_region_destroy (next_region);
 
-  cairo_region_subtract_rectangle (chunk_render->update_region, &rect);
+  gimp_projection_chunk_render_set_area (proj,
+                                         rect.x,     rect.y,
+                                         rect.width, rect.height);
 
-  if (cairo_region_is_empty (chunk_render->update_region))
+  return TRUE;
+}
+
+static void
+gimp_projection_chunk_render_set_area (GimpProjection *proj,
+                                       gint            x,
+                                       gint            y,
+                                       gint            w,
+                                       gint            h)
+{
+  GimpProjectionChunkRender *chunk_render = &proj->priv->chunk_render;
+  cairo_rectangle_int_t      rect;
+
+  rect.x      = x;
+  rect.y      = y;
+  rect.width  = w;
+  rect.height = h;
+
+  if (chunk_render->update_region)
     {
-      g_clear_pointer (&chunk_render->update_region, cairo_region_destroy);
+      cairo_region_subtract_rectangle (chunk_render->update_region, &rect);
+
+      if (cairo_region_is_empty (chunk_render->update_region))
+        g_clear_pointer (&chunk_render->update_region, cairo_region_destroy);
     }
 
   chunk_render->x      = rect.x;
@@ -1120,8 +1164,6 @@ gimp_projection_chunk_render_next_area (GimpProjection *proj)
 
   chunk_render->work_x = chunk_render->x;
   chunk_render->work_y = chunk_render->y;
-
-  return TRUE;
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]