[gimp] Bug 790810 - Nested layer groups lead to a deadlock with multithreading



commit caa3a98f04334152dbc378bb85bea3bab021c69f
Author: Ell <ell_se yahoo com>
Date:   Mon Mar 26 18:51:24 2018 -0400

    Bug 790810 - Nested layer groups lead to a deadlock with multithreading
    
    In gimp_operation_buffer_source_validate_process(), align the ROI
    to the tile grid *before* intersecting it with the validate-
    handler's dirty region.  This is necessary since, even though
    subsequent operations will only read data within the ROI, the
    entire tiles containing the ROI will be fetched, resulting in an
    area potentially greater than the ROI.  We need to validate this
    area in advance, or else it will be validated as part of the
    subsequent operations, which can lead into the same deadlock we're
    trying to prevent.

 app/operations/gimpoperationbuffersourcevalidate.c |  122 +++++++++-----------
 1 files changed, 53 insertions(+), 69 deletions(-)
---
diff --git a/app/operations/gimpoperationbuffersourcevalidate.c 
b/app/operations/gimpoperationbuffersourcevalidate.c
index 9f898f4..aae7892 100644
--- a/app/operations/gimpoperationbuffersourcevalidate.c
+++ b/app/operations/gimpoperationbuffersourcevalidate.c
@@ -64,10 +64,6 @@ static void           gimp_operation_buffer_source_validate_buffer_changed   (Ge
                                                                               const GeglRectangle            
   *rect,
                                                                               gpointer                       
    data);
 
-static void           gimp_operation_buffer_source_validate_buffer_validate  
(GimpOperationBufferSourceValidate *buffer_source_validate,
-                                                                              const cairo_rectangle_int_t    
   *rect,
-                                                                              gint                           
    level);
-
 
 G_DEFINE_TYPE (GimpOperationBufferSourceValidate, gimp_operation_buffer_source_validate,
                GEGL_TYPE_OPERATION_SOURCE)
@@ -255,43 +251,74 @@ gimp_operation_buffer_source_validate_process (GeglOperation        *operation,
            */
           if (n_threads > 1)
             {
+              gint                   shift_x;
+              gint                   shift_y;
+              gint                   tile_width;
+              gint                   tile_height;
               cairo_rectangle_int_t  rect;
               cairo_region_overlap_t overlap;
 
-              rect.x      = result->x;
-              rect.y      = result->y;
-              rect.width  = result->width;
-              rect.height = result->height;
+              g_object_get (buffer_source_validate->buffer,
+                            "shift-x",     &shift_x,
+                            "shift-y",     &shift_y,
+                            "tile-width",  &tile_width,
+                            "tile-height", &tile_height,
+                            NULL);
+
+              /* align the rectangle to the tile grid */
+              rect.x      = (gint) floor ((gdouble) (result->x                  + shift_x) / tile_width)  * 
tile_width;
+              rect.y      = (gint) floor ((gdouble) (result->y                  + shift_y) / tile_height) * 
tile_height;
+              rect.width  = (gint) ceil  ((gdouble) (result->x + result->width  + shift_x) / tile_width)  * 
tile_width  - rect.x;
+              rect.height = (gint) ceil  ((gdouble) (result->y + result->height + shift_y) / tile_height) * 
tile_height - rect.y;
 
+              /* check if the rectangle interescts with the dirty region */
               overlap = cairo_region_contains_rectangle (validate_handler->dirty_region,
                                                          &rect);
 
-              if (overlap == CAIRO_REGION_OVERLAP_IN)
-                {
-                  gimp_operation_buffer_source_validate_buffer_validate (
-                    buffer_source_validate, &rect, level);
-                }
-              else if (overlap == CAIRO_REGION_OVERLAP_PART)
+              if (overlap != CAIRO_REGION_OVERLAP_OUT)
                 {
-                  cairo_region_t *region;
-                  gint            n_rectangles;
-                  gint            i;
+                  GeglBufferIterator *iter;
 
-                  region = cairo_region_copy (validate_handler->dirty_region);
+                  /* if the rectangle is not entirely within the dirty
+                   * region ...
+                   */
+                  if (overlap == CAIRO_REGION_OVERLAP_PART)
+                    {
+                      cairo_region_t *region;
 
-                  cairo_region_intersect_rectangle (region, &rect);
+                      /* ... intersect it with region and use the result's
+                       * bounds
+                       */
+                      region = cairo_region_copy (validate_handler->dirty_region);
 
-                  n_rectangles = cairo_region_num_rectangles (region);
+                      cairo_region_intersect_rectangle (region, &rect);
+                      cairo_region_get_extents (region, &rect);
 
-                  for (i = 0; i < n_rectangles; i++)
-                    {
-                      cairo_region_get_rectangle (region, i, &rect);
+                      cairo_region_destroy (region);
 
-                      gimp_operation_buffer_source_validate_buffer_validate (
-                        buffer_source_validate, &rect, level);
+                      /* realign the rectangle to the tile grid */
+                      rect.x      = (gint) floor ((gdouble) (result->x                  + shift_x) / 
tile_width)  * tile_width;
+                      rect.y      = (gint) floor ((gdouble) (result->y                  + shift_y) / 
tile_height) * tile_height;
+                      rect.width  = (gint) ceil  ((gdouble) (result->x + result->width  + shift_x) / 
tile_width)  * tile_width  - rect.x;
+                      rect.height = (gint) ceil  ((gdouble) (result->y + result->height + shift_y) / 
tile_height) * tile_height - rect.y;
                     }
 
-                  cairo_region_destroy (region);
+                  rect.x -= shift_x;
+                  rect.y -= shift_y;
+
+                  /* iterate over the rectangle -- this implicitly causes
+                   * validation
+                   */
+                  iter = gegl_buffer_iterator_new (buffer,
+                                                   GEGL_RECTANGLE (rect.x,
+                                                                   rect.y,
+                                                                   rect.width,
+                                                                   rect.height),
+                                                   level, NULL,
+                                                   GEGL_BUFFER_READ,
+                                                   GEGL_ABYSS_NONE);
+
+                  while (gegl_buffer_iterator_next (iter));
                 }
             }
         }
@@ -314,46 +341,3 @@ gimp_operation_buffer_source_validate_buffer_changed (GeglBuffer          *buffe
   gegl_operation_invalidate (GEGL_OPERATION (buffer_source_validate),
                              rect, FALSE);
 }
-
-static void
-gimp_operation_buffer_source_validate_buffer_validate (GimpOperationBufferSourceValidate 
*buffer_source_validate,
-                                                       const cairo_rectangle_int_t       *rect,
-                                                       gint                               level)
-{
-  gint                shift_x;
-  gint                shift_y;
-  gint                tile_width;
-  gint                tile_height;
-  GeglRectangle       roi;
-  GeglBufferIterator *iter;
-
-  g_object_get (buffer_source_validate->buffer,
-                "shift-x",     &shift_x,
-                "shift-y",     &shift_y,
-                "tile-width",  &tile_width,
-                "tile-height", &tile_height,
-                NULL);
-
-  /* align rectangle to tile grid */
-
-  roi.x      = (gint) floor ((gdouble) (rect->x                + shift_x) / tile_width)  * tile_width;
-  roi.y      = (gint) floor ((gdouble) (rect->y                + shift_y) / tile_height) * tile_height;
-  roi.width  = (gint) ceil  ((gdouble) (rect->x + rect->width  + shift_x) / tile_width)  * tile_width  - 
roi.x;
-  roi.height = (gint) ceil  ((gdouble) (rect->y + rect->height + shift_y) / tile_height) * tile_height - 
roi.y;
-
-  roi.x -= shift_x;
-  roi.y -= shift_y;
-
-  /* intersect rectangle with abyss */
-
-  gegl_rectangle_intersect (&roi, &roi,
-                            gegl_buffer_get_abyss (buffer_source_validate->buffer));
-
-  /* iterate over rectangle -- this implicitly causes validation */
-
-  iter = gegl_buffer_iterator_new (buffer_source_validate->buffer,
-                                   &roi, level, NULL,
-                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
-
-  while (gegl_buffer_iterator_next (iter));
-}


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