static gboolean
gegl_operation_point_render_process (GeglOperation       *operation,
                                     GeglBuffer          *output,
                                     const GeglRectangle *result,
                                     gint                 level)
{
  GeglPad    *pad;
  const Babl *out_format;
  GeglOperationPointRenderClass *point_render_class;

  point_render_class = GEGL_OPERATION_POINT_RENDER_GET_CLASS (operation);

  pad        = gegl_node_get_pad (operation->node, "output");
  out_format = gegl_pad_get_format (pad);
  if (!out_format)
    {
      g_warning ("%s", gegl_node_get_debug_name (operation->node));
    }
  g_assert (out_format);

  if ((result->width > 0) && (result->height > 0))
    {
      GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, level, out_format, GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (i))
          point_render_class->process (operation, i->data[0], i->length, &i->roi[0], level);
    }
  return TRUE;
}
예제 #2
0
static void
gegl_dot_add_graph (GString     *string,
                    GeglNode    *node,
                    const gchar *label)
{
  GeglNode *graph = node;

  g_string_append_printf (string, "subgraph cluster_%s%p { graph [ label=\"%s %p\" fontsize=\"10\" ranksep=\"0.3\" nodesep=\"0.3\"]; node [ fontsize=\"10\" ];\n", label, node, label, node);

  {
    GSList *nodes = gegl_node_get_children (graph);
    GSList *entry = nodes;

    while (entry)
      {
        GeglNode *node = entry->data;

        if (node->is_graph)
          {
            gchar *name = g_strdup (gegl_node_get_debug_name (node));
            gchar *p    = name;
            while (*p)
              {
                if (*p == ' ' ||
                    *p == '-')
                  *p = '_';
                p++;
              }
            gegl_dot_add_graph (string, node, name);
            g_free (name);
          }
        else
          {
            gegl_dot_util_add_node (string, node);
          }

        entry = g_slist_next (entry);
      }

    g_slist_free (nodes);
  }

  {
    GSList *nodes = gegl_node_get_children (graph);
    GSList *entry = nodes;

    while (entry)
      {
        GeglNode *node = entry->data;

        gegl_dot_util_add_node_sink_edges (string, node);

        entry = g_slist_next (entry);
      }
    g_slist_free (nodes);
  }
  g_string_append_printf (string, "}\n");
}
예제 #3
0
static gboolean
gegl_operation_composer_process (GeglOperation        *operation,
                                 GeglOperationContext *context,
                                 const gchar          *output_prop,
                                 const GeglRectangle  *result,
                                 gint                  level)
{
  GeglOperationComposerClass *klass   = GEGL_OPERATION_COMPOSER_GET_CLASS (operation);
  GeglBuffer                 *input;
  GeglBuffer                 *aux;
  GeglBuffer                 *output;
  gboolean                    success = FALSE;

  if (strcmp (output_prop, "output"))
    {
      g_warning ("requested processing of %s pad on a composer", output_prop);
      return FALSE;
    }

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

  /* A composer with a NULL aux, can still be valid, the
   * subclass has to handle it.
   */
  if (input != NULL ||
      aux != NULL)
    {
      success = klass->process (operation, input, aux, output, result, level);

      if (output == GEGL_BUFFER (operation->node->cache))
        gegl_cache_computed (operation->node->cache, result);

      if (input)
        g_object_unref (input);
      if (aux)
        g_object_unref (aux);
    }
  else
    {
      g_warning ("%s received NULL input and aux",
                 gegl_node_get_debug_name (operation->node));
    }

  return success;
}
예제 #4
0
/* sets up the node's bounding box */
static void
gegl_have_visitor_visit_node (GeglVisitor *self,
                              GeglNode    *node)
{
  GeglOperation *operation;
  glong          time = gegl_ticks ();

  GEGL_VISITOR_CLASS (gegl_have_visitor_parent_class)->visit_node (self, node);
  if (!node)
    return;
  operation = node->operation;
  g_mutex_lock (node->mutex);
  node->have_rect = gegl_operation_get_bounding_box (operation);

  GEGL_NOTE (GEGL_DEBUG_PROCESS,
             "For \"%s\" have_rect = %d,%d %d×%d",
             gegl_node_get_debug_name (node),
             node->have_rect.x, node->have_rect.y, node->have_rect.width, node->have_rect.height);
  g_mutex_unlock (node->mutex);

  time = gegl_ticks () - time;
  gegl_instrument ("process", gegl_node_get_operation (node), time);
  gegl_instrument (gegl_node_get_operation (node), "defined-region", time);
}
예제 #5
0
static void
gegl_node_set_props (GeglNode *node,
                     va_list   var_args)
{
    const char *property_name;

    g_object_freeze_notify (G_OBJECT (node));

    property_name = va_arg (var_args, gchar *);
    while (property_name)
    {
        GValue      value = { 0, };
        GParamSpec *pspec = NULL;
        gchar      *error = NULL;

        if (!strcmp (property_name, "name"))
        {
            pspec = g_object_class_find_property (
                        G_OBJECT_GET_CLASS (G_OBJECT (node)), property_name);

            g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
            G_VALUE_COLLECT (&value, var_args, 0, &error);
            if (error)
            {
                g_warning ("%s: %s", G_STRFUNC, error);
                g_free (error);
                g_value_unset (&value);
                break;
            }
            g_object_set_property (G_OBJECT (node), property_name, &value);
            g_value_unset (&value);
        }
        else
        {
            if (node->operation)
            {
                pspec = g_object_class_find_property (
                            G_OBJECT_GET_CLASS (G_OBJECT (node->operation)), property_name);
            }
            if (!pspec)
            {
                g_warning ("%s:%s has no property named: '%s'",
                           G_STRFUNC,
                           gegl_node_get_debug_name (node), property_name);
                break;
            }
            if (!(pspec->flags & G_PARAM_WRITABLE))
            {
                g_warning ("%s: property (%s of operation class '%s' is not writable",
                           G_STRFUNC,
                           pspec->name,
                           G_OBJECT_TYPE_NAME (node->operation));
                break;
            }

            g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
            G_VALUE_COLLECT (&value, var_args, 0, &error);
            if (error)
            {
                g_warning ("%s: %s", G_STRFUNC, error);
                g_free (error);
                g_value_unset (&value);
                break;
            }
            g_object_set_property (G_OBJECT (node->operation), property_name, &value);
            g_value_unset (&value);
        }
        property_name = va_arg (var_args, gchar *);
    }
    g_object_thaw_notify (G_OBJECT (node));
}
예제 #6
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);
            }
        }
    }
}
GeglBuffer *
gegl_operation_context_get_target (GeglOperationContext *context,
                                   const gchar          *padname)
{
  GeglBuffer          *output;
  const GeglRectangle *result;
  const Babl          *format;
  GeglNode            *node;
  GeglOperation       *operation;

#if 0
  g_return_val_if_fail (GEGL_IS_OPERATION_CONTEXT (context), NULL);
#endif

  operation = context->operation;
  node = operation->node; /* <ick */
  format = gegl_operation_get_format (operation, padname);

  if (format == NULL)
    {
      g_warning ("no format for %s presuming RGBA float\n",
                 gegl_node_get_debug_name (node));
      format = babl_format ("RGBA float");
    }
  g_assert (format != NULL);
  g_assert (!strcmp (padname, "output"));

  result = &context->result_rect;

  if (result->width == 0 ||
      result->height == 0)
    {
      output = g_object_ref (emptybuf());
    }
  else if (node->dont_cache == FALSE &&
      ! GEGL_OPERATION_CLASS (G_OBJECT_GET_CLASS (operation))->no_cache)
    {
      GeglBuffer    *cache;
      cache = GEGL_BUFFER (gegl_node_get_cache (node));

      /* Only use the cache if the result is within the cache
       * extent. This is certainly not optimal. My gut feeling is that
       * the current caching mechanism needs to be redesigned
       */
      if (gegl_rectangle_contains (gegl_buffer_get_extent (cache), result))
        {
          output = g_object_ref (cache);
        }
      else
        {
          output = gegl_buffer_new_ram (result, format);
        }
    }
  else
    {
      output = gegl_buffer_new_ram (result, format);
    }

  gegl_operation_context_take_object (context, padname, G_OBJECT (output));
  return output;
}
예제 #8
0
void
gegl_dot_util_add_node (GString  *string,
                        GeglNode *node)
{
  g_string_append_printf (string, "op_%p [fontsize=\"10\" label=\"", node);

  /* We build the record from top to bottom */
  g_string_append_printf (string, "{");

  /* The first row is a list of output pads */
  {
    GSList  *pads       = gegl_node_get_pads (node);
    GSList  *entry      = pads;
    gboolean got_output = FALSE;

    g_string_append_printf (string, "{");

    while (entry)
      {
        GeglPad *pad = entry->data;
        if (gegl_pad_is_output (pad))
          {
            if (got_output)
              {
                g_string_append (string, "|");
              }
            got_output = TRUE;
            g_string_append_printf (string, "<%s>%s",
                                    gegl_pad_get_name (pad),
                                    gegl_pad_get_name (pad));
          }
        entry = g_slist_next (entry);
      }

    g_string_append_printf (string, "}|");
  }

  /* The second row is the operation name such as gegl:translate */
  g_string_append_printf (string, "%s |", gegl_node_get_debug_name (node));

  /* The next rows are property names and their values */
  if (1)
    {
      guint        n_properties;
      GParamSpec **properties = gegl_operation_list_properties (gegl_node_get_operation (node), &n_properties);
      guint        i;
      for (i = 0; i < n_properties; i++)
        {
          const gchar *name   = properties[i]->name;
          GValue       tvalue = { 0, };
          GValue       svalue = { 0, };

          if (properties[i]->value_type == GEGL_TYPE_BUFFER)
            continue;

          g_value_init (&svalue, G_TYPE_STRING);
          g_value_init (&tvalue, properties[i]->value_type);

          gegl_node_get_property (node, name, &tvalue);

          if (g_value_transform (&tvalue, &svalue))
            {
              gchar *sval = g_value_dup_string (&svalue);
              if (sval && strlen (sval) > 30)
                {
                  sval[28] = '.';
                  sval[29] = '.';
                  sval[30] = '\0';
                }
              if (sval)
                {
                  g_string_append_printf (string, "%s=%s | ", name, sval);
                  g_free (sval);
                }
              g_value_unset (&svalue);
            }
          g_value_unset (&tvalue);
        }
      g_free (properties);
    }

  /* The last row is input pads */
  {
    GSList  *pads      = gegl_node_get_pads (node);
    GSList  *entry     = pads;
    gboolean got_input = FALSE;

    g_string_append_printf (string, "{");

    while (entry)
      {
        GeglPad *pad = entry->data;
        if (gegl_pad_is_input (pad))
          {
            if (got_input)
              {
                g_string_append (string, "|");
              }
            got_input = TRUE;
            g_string_append_printf (string, "<%s>%s",
                                    gegl_pad_get_name (pad),
                                    gegl_pad_get_name (pad));
          }
        entry = g_slist_next (entry);
      }

    g_string_append_printf (string, "}");
  }

  g_string_append_printf (string, "}\"");
  g_string_append_printf (string, "shape=\"record\"];\n");
}
예제 #9
0
/**
 * 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;
}