Beispiel #1
0
static gboolean
process (GeglOperation        *operation,
         GeglOperationContext *context,
         const gchar          *output_pad,
         const GeglRectangle  *result,
         gint                  level)
{
    GeglProperties *o = GEGL_PROPERTIES (operation);

    if (o->buffer)
    {
        g_object_ref (o->buffer); /* Add an extra reference, since
				     * gegl_operation_set_data is
				     * stealing one.
				     */

        /* override core behaviour, by resetting the buffer in the operation_context */
        gegl_operation_context_take_object (context, "output",
                                            G_OBJECT (o->buffer));
        /* mark that this buffer should not be used for in-place
         * processing.
         */
        gegl_object_set_has_forked (G_OBJECT (o->buffer));
    }
    return TRUE;
}
GeglBuffer *
gegl_graph_get_shared_empty (GeglGraphTraversal *path)
{
  if (!path->shared_empty)
    {
      path->shared_empty = gegl_buffer_new_ram (GEGL_RECTANGLE (0, 0, 0, 0),
                                                gegl_babl_rgba_linear_float ());
      gegl_object_set_has_forked (G_OBJECT (path->shared_empty));
    }
  return path->shared_empty;
}
Beispiel #3
0
static gboolean
gegl_crop_process (GeglOperation        *operation,
                   GeglOperationContext *context,
                   const gchar          *output_prop,
                   const GeglRectangle  *result,
                   gint                  level)
{
  GeglProperties *o = GEGL_PROPERTIES (operation);
  GeglBuffer     *input;
  gboolean        success = FALSE;
  GeglRectangle   extent;

  extent.x      = o->x;
  extent.y      = o->y;
  extent.width  = o->width;
  extent.height = o->height;

  input = gegl_operation_context_get_source (context, "input");

  if (input)
    {
      GeglBuffer *output = gegl_buffer_create_sub_buffer (input, &extent);

      if (gegl_object_get_has_forked (G_OBJECT (input)))
        gegl_object_set_has_forked (G_OBJECT (output));

      gegl_operation_context_take_object (context, "output", G_OBJECT (output));

      g_object_unref (input);
      success = TRUE;
    }
  else
    {
      g_warning ("%s got NULL input pad", gegl_node_get_operation (operation->node));
    }

  return success;
}
Beispiel #4
0
/* this is the visitor that does the real computations for GEGL */
static void
gegl_eval_visitor_visit_pad (GeglVisitor *self,
                             GeglPad     *pad)
{
  GeglNode        *node       = gegl_pad_get_node (pad);
  gpointer         context_id = self->context_id;
  GeglOperationContext *context    = gegl_node_get_context (node, context_id);
  GeglOperation   *operation  = node->operation;

  GEGL_VISITOR_CLASS (gegl_eval_visitor_parent_class)->visit_pad (self, pad);

  if (gegl_pad_is_output (pad))
    {
      /* processing only really happens for output pads */
      if (context->cached)
        {
          GEGL_NOTE (GEGL_DEBUG_PROCESS, "Using cache for pad '%s' on \"%s\"", gegl_pad_get_name (pad), gegl_node_get_debug_name (node));
          gegl_operation_context_set_object (context,
                                             gegl_pad_get_name (pad),
                                             G_OBJECT (node->cache));
        }
      else
        {
          glong time      = gegl_ticks ();

          /* Make the operation do it's actual processing */
          GEGL_NOTE (GEGL_DEBUG_PROCESS, "For \"%s\" processing pad '%s' result_rect = %d, %d %d×%d",
                     gegl_pad_get_name (pad), gegl_node_get_debug_name (node),
                     context->result_rect.x, context->result_rect.y, context->result_rect.width, context->result_rect.height);
          gegl_operation_process (operation, context, gegl_pad_get_name (pad),
                                  &context->result_rect);
          time      = gegl_ticks () - time;

          gegl_instrument ("process", gegl_node_get_operation (node), time);

          if (gegl_pad_get_num_connections (pad) > 1)
            {
              /* Mark buffers that have been consumed by different parts of the
               * graph so that in-place processing can be avoided on them.
               */
              GValue *value;
              GeglBuffer *buffer;
              value = gegl_operation_context_get_value (context, gegl_pad_get_name (pad));
              if (value)
                {
                  buffer = g_value_get_object (value);
                  if (buffer)
                    gegl_object_set_has_forked (buffer);
                }
            }
        }
    }
  else if (gegl_pad_is_input (pad))
    {
      GeglPad *source_pad = gegl_pad_get_connected_to (pad);

      /* the work needed to be done on input pads is to set the
       * data from the corresponding output pad it is connected to
       */
      if (source_pad)
        {
          GValue           value          = { 0 };
          GParamSpec      *prop_spec      = gegl_pad_get_param_spec (pad);
          GeglNode        *source_node    = gegl_pad_get_node (source_pad);
          GeglOperationContext *source_context = gegl_node_get_context (source_node, context_id);

          g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec));

          gegl_operation_context_get_property (source_context,
                                          gegl_pad_get_name (source_pad),
                                          &value);

          if (!g_value_get_object (&value) &&
              !g_object_get_data (G_OBJECT (source_node), "graph"))
            g_warning ("eval-visitor encountered a NULL buffer passed from: %s.%s-[%p]",
                       gegl_node_get_debug_name (source_node),
                       gegl_pad_get_name (source_pad),
                       g_value_get_object (&value));

          gegl_operation_context_set_property (context,
                                          gegl_pad_get_name (pad),
                                          &value);
          /* reference counting for this source dropped to zero, freeing up */
          if (-- gegl_node_get_context (
                     gegl_pad_get_node (source_pad), context_id)->refs == 0 &&
              g_value_get_object (&value))
            {
              gegl_operation_context_remove_property (
                 gegl_node_get_context (
                    gegl_pad_get_node (source_pad), context_id),
                    gegl_pad_get_name (source_pad));
            }

          g_value_unset (&value);

	  /* processing for sink operations that accepts partial consumption
             and thus probably are being processed by the processor from the
             this very operation.
           */
          if (GEGL_IS_OPERATION_SINK (operation) &&
              !gegl_operation_sink_needs_full (operation))
            {
              GEGL_NOTE (GEGL_DEBUG_PROCESS, "Processing pad '%s' on \"%s\"", gegl_pad_get_name (pad), gegl_node_get_debug_name (node));
              gegl_operation_process (operation, context, "output",
                &context->result_rect);
            }
        }
    }
}
Beispiel #5
0
static gboolean
gegl_affine_process (GeglOperation        *operation,
                     GeglOperationContext *context,
                     const gchar          *output_prop,
                     const GeglRectangle  *result)
{
  GeglBuffer          *input;
  GeglBuffer          *output;
  GeglMatrix3          matrix;
  OpAffine            *affine = (OpAffine *) operation;

  gegl_affine_create_composite_matrix (affine, &matrix);

  if (gegl_affine_is_intermediate_node (affine) ||
      gegl_matrix3_is_identity (&matrix))
    {
      /* passing straight through (like gegl:nop) */
      input  = gegl_operation_context_get_source (context, "input");
      if (!input)
        {
          g_warning ("transform received NULL input");
          return FALSE;
        }

      gegl_operation_context_take_object (context, "output", G_OBJECT (input));
    }
  else if (gegl_affine_matrix3_allow_fast_translate (&matrix) ||
           (gegl_matrix3_is_translate (&matrix) &&
            ! strcmp (affine->filter, "nearest")))
    {
      /* doing a buffer shifting trick, (enhanced nop) */
      input  = gegl_operation_context_get_source (context, "input");

      output = g_object_new (GEGL_TYPE_BUFFER,
                             "source",    input,
                             "shift-x",   (int)-matrix.coeff[0][2],
                             "shift-y",   (int)-matrix.coeff[1][2],
                             "abyss-width", -1,  /* turn of abyss
                                                    (relying on abyss
                                                    of source) */
                         NULL);

      if (gegl_object_get_has_forked (input))
        gegl_object_set_has_forked (output);

      gegl_operation_context_take_object (context, "output", G_OBJECT (output));

      if (input != NULL)
        g_object_unref (input);
    }
  else if (gegl_affine_matrix3_allow_fast_reflect_x (&matrix))
    {
      GeglRectangle      src_rect;
      GeglSampler       *sampler;
      GeglRectangle      context_rect;

      input  = gegl_operation_context_get_source (context, "input");
      if (!input)
        {
          g_warning ("transform received NULL input");
          return FALSE;
        }

      output = gegl_operation_context_get_target (context, "output");

      src_rect = gegl_operation_get_required_for_output (operation, "output", result);
      src_rect.y += 1;

      sampler = gegl_buffer_sampler_new (input, babl_format("RaGaBaA float"),
          gegl_sampler_type_from_string (affine->filter));
      context_rect = *gegl_sampler_get_context_rect (sampler);

      src_rect.width -= context_rect.width;
      src_rect.height -= context_rect.height;

      gegl_affine_fast_reflect_x (output, input, result, &src_rect);
      g_object_unref (sampler);

      if (input != NULL)
        g_object_unref (input);
    }
  else if (gegl_affine_matrix3_allow_fast_reflect_y (&matrix))
    {
      GeglRectangle      src_rect;
      GeglSampler       *sampler;
      GeglRectangle      context_rect;

      input  = gegl_operation_context_get_source (context, "input");
      if (!input)
        {
          g_warning ("transform received NULL input");
          return FALSE;
        }

      output = gegl_operation_context_get_target (context, "output");

      src_rect = gegl_operation_get_required_for_output (operation, "output", result);
      src_rect.x += 1;

      sampler = gegl_buffer_sampler_new (input, babl_format("RaGaBaA float"),
          gegl_sampler_type_from_string (affine->filter));
      context_rect = *gegl_sampler_get_context_rect (sampler);

      src_rect.width -= context_rect.width;
      src_rect.height -= context_rect.height;

      gegl_affine_fast_reflect_y (output, input, result, &src_rect);
      g_object_unref (sampler);

      if (input != NULL)
        g_object_unref (input);
    }
  else
    {
      /* for all other cases, do a proper resampling */
      GeglSampler *sampler;

      input  = gegl_operation_context_get_source (context, "input");
      output = gegl_operation_context_get_target (context, "output");

      sampler = gegl_buffer_sampler_new (input, babl_format("RaGaBaA float"),
          gegl_sampler_type_from_string (affine->filter));
      affine_generic (output, input, &matrix, sampler);
      g_object_unref (sampler);

      if (input != NULL)
        g_object_unref (input);
    }

  return TRUE;
}
/**
 * gegl_graph_process:
 * @path: The traversal path
 *
 * Process the prepared request. This will return the
 * resulting buffer from the final node, or NULL if
 * that node is a sink.
 *
 * If gegl_graph_prepare_request has not been called
 * the behavior of this function is undefined.
 *
 * Return value: (transfer full): The result of the graph, or NULL if
 * there is no output pad.
 */
GeglBuffer *
gegl_graph_process (GeglGraphTraversal *path,
                    gint                level)
{
  GList *list_iter = NULL;
  GeglBuffer *result = NULL;
  GeglOperationContext *context = NULL;
  GeglOperationContext *last_context = NULL;
  GeglBuffer *operation_result = NULL;

  for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
    {
      GeglNode *node = GEGL_NODE (list_iter->data);
      GeglOperation *operation = node->operation;
      g_return_val_if_fail (node, NULL);
      g_return_val_if_fail (operation, NULL);
      
      GEGL_INSTRUMENT_START();

      operation_result = NULL;

      if (last_context)
        gegl_operation_context_purge (last_context);
      
      context = g_hash_table_lookup (path->contexts, node);
      g_return_val_if_fail (context, NULL);

      GEGL_NOTE (GEGL_DEBUG_PROCESS,
                 "Will process %s result_rect = %d, %d %d×%d",
                 gegl_node_get_debug_name (node),
                 context->result_rect.x, context->result_rect.y, context->result_rect.width, context->result_rect.height);
      
      if (context->need_rect.width > 0 && context->need_rect.height > 0)
        {
          if (context->cached)
            {
              GEGL_NOTE (GEGL_DEBUG_PROCESS,
                         "Using cached result for %s",
                         gegl_node_get_debug_name (node));
              operation_result = GEGL_BUFFER (node->cache);
            }
          else
            {
              /* provide something on input pad, always - this makes having
                 behavior depending on it not being set.. not work, is
                 sacrifising that worth it?
               */
              if (gegl_node_has_pad (node, "input") &&
                  !gegl_operation_context_get_object (context, "input"))
                {
                  gegl_operation_context_set_object (context, "input", G_OBJECT (gegl_graph_get_shared_empty(path)));
                }

              context->level = level;

              /* note: this hard-coding of "output" makes some more custom
               * graph topologies harder than neccesary.
               */
              gegl_operation_process (operation, context, "output", &context->need_rect, context->level);
              operation_result = GEGL_BUFFER (gegl_operation_context_get_object (context, "output"));

              if (operation_result && operation_result == (GeglBuffer *)operation->node->cache)
                gegl_cache_computed (operation->node->cache, &context->need_rect, level);
            }
        }
      else
        {
          operation_result = NULL;
        }

      if (operation_result)
        {
          GeglPad *output_pad = gegl_node_get_pad (node, "output");
          GList   *targets = gegl_graph_get_connected_output_contexts (path, output_pad);
          GList   *targets_iter;

          GEGL_NOTE (GEGL_DEBUG_PROCESS,
                     "Will deliver the results of %s:%s to %d targets",
                     gegl_node_get_debug_name (node),
                     "output",
                     g_list_length (targets));

          if (g_list_length (targets) > 1)
            gegl_object_set_has_forked (G_OBJECT (operation_result));

          for (targets_iter = targets; targets_iter; targets_iter = g_list_next (targets_iter))
            {
              ContextConnection *target_con = targets_iter->data;
              gegl_operation_context_set_object (target_con->context, target_con->name, G_OBJECT (operation_result));
            }
          g_list_free_full (targets, free_context_connection);
        }
      last_context = context;

      GEGL_INSTRUMENT_END ("process", gegl_node_get_operation (node));
    }
  if (last_context)
    {
      if (operation_result)
        result = g_object_ref (operation_result);
      else if (gegl_node_has_pad (last_context->operation->node, "output"))
        result = g_object_ref (gegl_graph_get_shared_empty (path));
      gegl_operation_context_purge (last_context);
    }

  return result;
}
Beispiel #7
0
static gboolean
process (GeglOperation        *operation,
         GeglOperationContext *context,
         const gchar          *output_prop,
         const GeglRectangle  *result,
         gint                  level)
{
  GeglProperties  *o    = GEGL_PROPERTIES (operation);
  WarpPrivate     *priv = (WarpPrivate*) o->user_data;

  GeglBuffer      *input;

  gdouble          spacing = MAX (o->size * o->spacing, 0.5);
  gdouble          dist;
  gint             stamps;
  gint             i;
  gdouble          t;

  GeglPathPoint    prev, next, lerp;
  GeglPathList    *event;
  WarpPointList   *processed_event;
  WarpPointList  **processed_event_ptr;

  if (!o->stroke || strcmp (output_prop, "output"))
    return FALSE;

  /* if the previously processed stroke is valid, the cached buffer can be
   * passed as output right away.
   */
  if (priv->processed_stroke_valid)
    {
      g_assert (priv->buffer != NULL);

      gegl_operation_context_set_object (context,
                                         "output", G_OBJECT (priv->buffer));

      return TRUE;
    }

  /* ... otherwise, we need to check if the previously processed stroke is an
   * initial segment of the current stroke ...
   */

  event               = gegl_path_get_path (o->stroke);
  processed_event     = priv->processed_stroke;
  processed_event_ptr = &priv->processed_stroke;

  while (event && processed_event)
    {
      if (event->d.point[0].x != processed_event->point.x ||
          event->d.point[0].y != processed_event->point.y)
        {
          break;
        }

      processed_event_ptr = &processed_event->next;

      event           = event->next;
      processed_event = processed_event->next;
    }

  /* if the loop stopped before we reached the last event of the processed
   * stroke, it's not an initial segment, and we need to clear the cache, and
   * process the entire stroke.
   */
  if (processed_event)
    {
      clear_cache (o);

      event               = gegl_path_get_path (o->stroke);
      processed_event_ptr = &priv->processed_stroke;
    }
  /* otherwise, we simply continue processing remaining stroke on top of the
   * previously processed buffer.
   */

  /* intialize the cached buffer if we don't already have one. */
  if (! priv->buffer)
    {
      input = GEGL_BUFFER (gegl_operation_context_get_object (context,
                                                              "input"));

      priv->buffer = gegl_buffer_dup (input);

      /* we pass the buffer as output directly while keeping it cached, so mark
       * it as forked.
       */
      gegl_object_set_has_forked (G_OBJECT (priv->buffer));
    }

  if (event)
    {
      /* is this the first event of the stroke? */
      if (! priv->processed_stroke)
        {
          prev = *(event->d.point);

          priv->last_x = prev.x;
          priv->last_y = prev.y;
        }
      else
        {
          prev.x = priv->last_x;
          prev.y = priv->last_y;
        }

      for (; event; event = event->next)
        {
          next = *(event->d.point);
          dist = gegl_path_point_dist (&next, &prev);
          stamps = floor (dist / spacing) + 1;

          /* stroke the current segment, such that there's always a stamp at
           * its final endpoint, and at positive integer multiples of
           * `spacing` away from it.
           */

          if (stamps == 1)
            {
              stamp (o, next.x, next.y);
            }
          else
            {
              for (i = 0; i < stamps; i++)
                {
                  t = 1.0 - ((stamps - i - 1) * spacing) / dist;

                  gegl_path_point_lerp (&lerp, &prev, &next, t);
                  stamp (o, lerp.x, lerp.y);
                }
            }

          prev = next;

          /* append the current event to the processed path. */
          processed_event        = g_slice_new (WarpPointList);
          processed_event->point = next;

          *processed_event_ptr = processed_event;
          processed_event_ptr  = &processed_event->next;
        }

      *processed_event_ptr = NULL;
    }

  priv->processed_stroke_valid = TRUE;

  /* pass the processed buffer as output */
  gegl_operation_context_set_object (context,
                                     "output", G_OBJECT (priv->buffer));

  return TRUE;
}