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; }
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"); }
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; }
/* 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); }
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)); }
/* 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; }
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"); }
/** * 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; }