[gegl] operation: add gegl_operation_context_dup_input_maybe_copy()



commit 9cb3c7a25b21983709a227d7d27cf1506eb8ffb8
Author: Ell <ell_se yahoo com>
Date:   Wed Dec 13 03:19:02 2017 -0500

    operation: add gegl_operation_context_dup_input_maybe_copy()
    
    gegl_operation_context_dup_input_maybe_copy() takes a ROI, and
    returns either a reference to the input buffer, or a copy of the
    input buffer, containing (at least) the region required to process
    ROI, if the copy has a low-enough overhead.  Note that the copied
    input-buffer tiles are generally COWed, so this is rather cheap.
    
    This is useful for threaded ops, which can use this function to
    create a separate copy of the input buffer for each thread, to
    avoid contention over the input's tile-storage lock.  See the next
    commit.

 gegl/operation/gegl-operation-context.c |   97 +++++++++++++++++++++++++++++++
 gegl/operation/gegl-operation-context.h |   11 ++-
 2 files changed, 104 insertions(+), 4 deletions(-)
---
diff --git a/gegl/operation/gegl-operation-context.c b/gegl/operation/gegl-operation-context.c
index 74429ed..98c43e0 100644
--- a/gegl/operation/gegl-operation-context.c
+++ b/gegl/operation/gegl-operation-context.c
@@ -21,6 +21,7 @@
 #include "config.h"
 
 #include <string.h>
+#include <math.h>
 
 #include <glib-object.h>
 
@@ -29,6 +30,7 @@
 #include "gegl-operation-context.h"
 #include "gegl-operation-context-private.h"
 #include "gegl-node-private.h"
+#include "gegl-buffer-private.h"
 #include "gegl-config.h"
 
 #include "operation/gegl-operation.h"
@@ -397,3 +399,98 @@ gegl_operation_context_get_output_maybe_in_place (GeglOperation *operation,
     }
   return output;
 }
+
+GeglBuffer *
+gegl_operation_context_dup_input_maybe_copy (GeglOperationContext *context,
+                                             const gchar          *padname,
+                                             const GeglRectangle  *roi)
+{
+  GeglBuffer    *input;
+  GeglBuffer    *output;
+  GeglBuffer    *result;
+  GeglRectangle  required;
+  GeglRectangle  temp;
+  gint           shift_x;
+  gint           shift_y;
+  gint           tile_width;
+  gint           tile_height;
+
+  input = GEGL_BUFFER (gegl_operation_context_get_object (context, padname));
+
+  if (! input)
+    return NULL;
+
+  /* return input directly when processing a level greater than 0, since
+   * gegl_buffer_copy() only copies level-0 tiles
+   */
+  if (context->level > 0)
+    return g_object_ref (input);
+
+  output = GEGL_BUFFER (gegl_operation_context_get_object (context, "output"));
+
+  /* return input directly when processing in-place, otherwise, the copied
+   * input buffer will occupy space in the cache after the original is modified
+   */
+  if (input == output)
+    return g_object_ref (input);
+
+  /* get required region to copy */
+  required = gegl_operation_get_required_for_output (context->operation,
+                                                     padname, roi);
+
+  /* return input directly if the required rectangle is infinite, so that we
+   * don't attempt to copy an infinite region
+   */
+  if (gegl_rectangle_is_infinite_plane (&required))
+    return g_object_ref (input);
+
+  /* align required region to the tile grid */
+  shift_x     = input->shift_x;
+  shift_y     = input->shift_y;
+  tile_width  = input->tile_width;
+  tile_height = input->tile_height;
+
+  temp.x      = (gint) floor ((gdouble) (required.x                   + shift_x) / tile_width)  * tile_width;
+  temp.y      = (gint) floor ((gdouble) (required.y                   + shift_y) / tile_height) * 
tile_height;
+  temp.width  = (gint) ceil  ((gdouble) (required.x + required.width  + shift_x) / tile_width)  * tile_width 
 - temp.x;
+  temp.height = (gint) ceil  ((gdouble) (required.y + required.height + shift_y) / tile_height) * 
tile_height - temp.y;
+
+  temp.x -= shift_x;
+  temp.y -= shift_y;
+
+  required = temp;
+
+  /* intersect required region with input abyss */
+  gegl_rectangle_intersect (&required, &required, &input->abyss);
+
+  /* create new buffer with similar characteristics to the input buffer */
+  result = g_object_new (GEGL_TYPE_BUFFER,
+                         "format",       input->soft_format,
+                         "x",            input->extent.x,
+                         "y",            input->extent.y,
+                         "width",        input->extent.width,
+                         "height",       input->extent.height,
+                         "abyss-x",      input->abyss.x,
+                         "abyss-y",      input->abyss.y,
+                         "abyss-width",  input->abyss.width,
+                         "abyss-height", input->abyss.height,
+                         "shift-x",      shift_x,
+                         "shift-y",      shift_y,
+                         "tile-width",   tile_width,
+                         "tile-height",  tile_height,
+                         NULL);
+
+  /* if the tile size doesn't match, bail */
+  if (result->tile_width != tile_width || result->tile_height != tile_height)
+    {
+      g_object_unref (result);
+
+      return g_object_ref (input);
+    }
+
+  /* copy required region from input to result -- tiles will generally be COWed */
+  gegl_buffer_copy (input,  &required, GEGL_ABYSS_NONE,
+                    result, &required);
+
+  return result;
+}
diff --git a/gegl/operation/gegl-operation-context.h b/gegl/operation/gegl-operation-context.h
index 1437620..a6e5279 100644
--- a/gegl/operation/gegl-operation-context.h
+++ b/gegl/operation/gegl-operation-context.h
@@ -45,10 +45,13 @@ gint            gegl_operation_context_get_level       (GeglOperationContext *se
 
 /* the rest of these functions are for internal use only */
 
-GeglBuffer *    gegl_operation_context_get_output_maybe_in_place (GeglOperation *operation,
-                                                            GeglOperationContext *context,
-                                                            GeglBuffer    *input,
-                                                            const GeglRectangle *roi);
+GeglBuffer *    gegl_operation_context_get_output_maybe_in_place (GeglOperation        *operation,
+                                                                  GeglOperationContext *context,
+                                                                  GeglBuffer           *input,
+                                                                  const GeglRectangle  *roi);
+GeglBuffer *    gegl_operation_context_dup_input_maybe_copy      (GeglOperationContext *context,
+                                                                  const gchar          *padname,
+                                                                  const GeglRectangle  *roi);
 
 
 G_END_DECLS


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