static void gimp_projection_construct_gegl (GimpProjection *proj, gint x, gint y, gint w, gint h) { GeglNode *sink; GeglRectangle rect; sink = gimp_projection_get_sink_node (proj); rect.x = x; rect.y = y; rect.width = w; rect.height = h; if (! proj->processor) proj->processor = gegl_node_new_processor (sink, &rect); else gegl_processor_set_rectangle (proj->processor, &rect); while (gegl_processor_work (proj->processor, NULL)); /* FIXME: Reuse it when it can handle dirty rects when painting * properly */ g_object_unref (proj->processor); proj->processor = NULL; }
void gimp_applicator_apply (GimpApplicator *applicator, GeglBuffer *src_buffer, GeglBuffer *apply_buffer, gint apply_buffer_x, gint apply_buffer_y, gdouble opacity, GimpLayerModeEffects paint_mode) { gint width = gegl_buffer_get_width (apply_buffer); gint height = gegl_buffer_get_height (apply_buffer); if (applicator->src_buffer != src_buffer) { applicator->src_buffer = src_buffer; gegl_node_set (applicator->src_node, "buffer", src_buffer, NULL); } if (applicator->apply_buffer != apply_buffer) { applicator->apply_buffer = apply_buffer; gegl_node_set (applicator->apply_src_node, "buffer", apply_buffer, NULL); } gegl_node_set (applicator->apply_offset_node, "x", (gdouble) apply_buffer_x, "y", (gdouble) apply_buffer_y, NULL); if ((applicator->opacity != opacity) || (applicator->paint_mode != paint_mode)) { applicator->opacity = opacity; applicator->paint_mode = paint_mode; gimp_gegl_mode_node_set (applicator->mode_node, paint_mode, opacity, FALSE); } gegl_processor_set_rectangle (applicator->processor, GEGL_RECTANGLE (apply_buffer_x, apply_buffer_y, width, height)); while (gegl_processor_work (applicator->processor, NULL)); }
static gboolean test_change_processor_rect_do_test (GeglProcessor *processor, const GeglRectangle *rect, GeglNode *sink) { gint i = 0; gboolean result = TRUE; float expected_result_buffer[4] = { 1.0, 1.0, 1.0, 1.0 }; float result_buffer[4] = { 0, }; GeglBuffer *buffer = NULL; gegl_node_set (sink, "buffer", &buffer, NULL); gegl_processor_set_rectangle (processor, rect); while (gegl_processor_work (processor, NULL)); gegl_buffer_get (buffer, rect, 1.0, babl_format ("RGBA float"), result_buffer, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); /* Compare with a small epsilon to account for accumulated error */ for(i = 0; i < G_N_ELEMENTS (expected_result_buffer); i++) result = result && FLOATS_EQUAL (expected_result_buffer[i], result_buffer[i]); gegl_node_set (sink, "buffer", NULL, NULL); g_object_unref (buffer); return result; }
static gboolean task_monitor(ViewHelper *self) { if (!self->processor || !self->node) { return FALSE; } // PERFORMANCE: combine all the rects added to the queue during a single // iteration of the main loop somehow if (!self->currently_processed_rect) { if (g_queue_is_empty(self->processing_queue)) { // Unregister worker self->monitor_id = 0; return FALSE; } else { // Fetch next rect to process self->currently_processed_rect = (GeglRectangle *)g_queue_pop_tail(self->processing_queue); g_assert(self->currently_processed_rect); gegl_processor_set_rectangle(self->processor, self->currently_processed_rect); } } gboolean processing_done = !gegl_processor_work(self->processor, NULL); if (processing_done) { // Go to next region if (self->currently_processed_rect) { g_free(self->currently_processed_rect); } self->currently_processed_rect = NULL; } return TRUE; }
gboolean gimp_gegl_apply_cached_operation (GeglBuffer *src_buffer, GimpProgress *progress, const gchar *undo_desc, GeglNode *operation, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect, GeglBuffer *cache, const GeglRectangle *valid_rects, gint n_valid_rects, gboolean cancellable) { GeglNode *gegl; GeglNode *dest_node; GeglRectangle rect = { 0, }; GeglProcessor *processor = NULL; gboolean progress_started = FALSE; gdouble value; gboolean cancel = FALSE; g_return_val_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer), FALSE); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE); g_return_val_if_fail (GEGL_IS_NODE (operation), FALSE); g_return_val_if_fail (GEGL_IS_BUFFER (dest_buffer), FALSE); g_return_val_if_fail (cache == NULL || GEGL_IS_BUFFER (cache), FALSE); g_return_val_if_fail (valid_rects == NULL || cache != NULL, FALSE); g_return_val_if_fail (valid_rects == NULL || n_valid_rects != 0, FALSE); if (dest_rect) { rect = *dest_rect; } else { rect = *GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (dest_buffer), gegl_buffer_get_height (dest_buffer)); } gegl = gegl_node_new (); if (! gegl_node_get_parent (operation)) gegl_node_add_child (gegl, operation); if (src_buffer && gegl_node_has_pad (operation, "input")) { GeglNode *src_node; /* dup() because reading and writing the same buffer doesn't * work with area ops when using a processor. See bug #701875. */ if (progress && (src_buffer == dest_buffer)) src_buffer = gegl_buffer_dup (src_buffer); else g_object_ref (src_buffer); src_node = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", src_buffer, NULL); g_object_unref (src_buffer); gegl_node_connect_to (src_node, "output", operation, "input"); } dest_node = gegl_node_new_child (gegl, "operation", "gegl:write-buffer", "buffer", dest_buffer, NULL); gegl_node_connect_to (operation, "output", dest_node, "input"); if (progress) { processor = gegl_node_new_processor (dest_node, &rect); if (gimp_progress_is_active (progress)) { if (undo_desc) gimp_progress_set_text_literal (progress, undo_desc); progress_started = FALSE; cancellable = FALSE; } else { gimp_progress_start (progress, cancellable, "%s", undo_desc); if (cancellable) g_signal_connect (progress, "cancel", G_CALLBACK (gimp_gegl_apply_operation_cancel), &cancel); progress_started = TRUE; } } if (cache) { cairo_region_t *region; gint all_pixels; gint done_pixels = 0; gint n_rects; gint i; region = cairo_region_create_rectangle ((cairo_rectangle_int_t *) &rect); all_pixels = rect.width * rect.height; for (i = 0; i < n_valid_rects; i++) { gegl_buffer_copy (cache, valid_rects + i, GEGL_ABYSS_NONE, dest_buffer, valid_rects + i); cairo_region_subtract_rectangle (region, (cairo_rectangle_int_t *) valid_rects + i); done_pixels += valid_rects[i].width * valid_rects[i].height; if (progress) gimp_progress_set_value (progress, (gdouble) done_pixels / (gdouble) all_pixels); } n_rects = cairo_region_num_rectangles (region); for (i = 0; ! cancel && (i < n_rects); i++) { cairo_rectangle_int_t render_rect; cairo_region_get_rectangle (region, i, &render_rect); if (progress) { gint rect_pixels = render_rect.width * render_rect.height; #ifdef REUSE_PROCESSOR gegl_processor_set_rectangle (processor, (GeglRectangle *) &render_rect); #else g_object_unref (processor); processor = gegl_node_new_processor (dest_node, (GeglRectangle *) &render_rect); #endif while (! cancel && gegl_processor_work (processor, &value)) { gimp_progress_set_value (progress, ((gdouble) done_pixels + value * rect_pixels) / (gdouble) all_pixels); if (cancellable) while (! cancel && g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE); } done_pixels += rect_pixels; } else { gegl_node_blit (dest_node, 1.0, (GeglRectangle *) &render_rect, NULL, NULL, 0, GEGL_BLIT_DEFAULT); } } cairo_region_destroy (region); } else { if (progress) { while (! cancel && gegl_processor_work (processor, &value)) { gimp_progress_set_value (progress, value); if (cancellable) while (! cancel && g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE); } } else { gegl_node_blit (dest_node, 1.0, &rect, NULL, NULL, 0, GEGL_BLIT_DEFAULT); } } if (processor) g_object_unref (processor); g_object_unref (gegl); if (progress_started) { gimp_progress_end (progress); if (cancellable) g_signal_handlers_disconnect_by_func (progress, gimp_gegl_apply_operation_cancel, &cancel); } return ! cancel; }