1 /* This file is part of GEGL
2 *
3 * GEGL is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 3 of the License, or (at your option) any later version.
7 *
8 * GEGL is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15 *
16 * Copyright 2007-2012,2014,2015,2017 Øyvind Kolås
17 * 2015 Debarshi Ray
18 */
19
20 #include "config.h"
21
22 #include <glib-object.h>
23
24 #include "gegl.h"
25 #include "gegl-types-internal.h"
26 #include "gegl-debug.h"
27 #include "gegl-region.h"
28 #include "graph/gegl-node-private.h"
29
30 #include "operation/gegl-operation-context.h"
31 #include "operation/gegl-operation-context-private.h"
32 #include "operation/gegl-operation-sink.h"
33
34 #include "gegl-config.h"
35 #include "gegl-processor.h"
36 #include "gegl-processor-private.h"
37
38 #include "graph/gegl-visitor.h"
39 #include "graph/gegl-callback-visitor.h"
40 #include "graph/gegl-visitable.h"
41
42 #include "opencl/gegl-cl.h"
43
44 enum
45 {
46 PROP_0,
47 PROP_NODE,
48 PROP_CHUNK_SIZE,
49 PROP_PROGRESS,
50 PROP_RECTANGLE
51 };
52
53
54 static void gegl_processor_class_init (GeglProcessorClass *klass);
55 static void gegl_processor_init (GeglProcessor *self);
56 static void gegl_processor_finalize (GObject *self_object);
57 static void gegl_processor_set_property (GObject *gobject,
58 guint prop_id,
59 const GValue *value,
60 GParamSpec *pspec);
61 static void gegl_processor_get_property (GObject *gobject,
62 guint prop_id,
63 GValue *value,
64 GParamSpec *pspec);
65 static void gegl_processor_set_node (GeglProcessor *processor,
66 GeglNode *node);
67 static void gegl_processor_constructed (GObject *object);
68 static gdouble gegl_processor_progress (GeglProcessor *processor);
69 static gint gegl_processor_get_band_size(gint size) G_GNUC_CONST;
70
71
72 struct _GeglProcessor
73 {
74 GObject parent;
75 GeglNode *node;
76 GeglNode *real_node;
77 GeglRectangle rectangle;
78 GeglRectangle rectangle_unscaled;
79 GeglNode *input;
80 gint level;
81 GeglOperationContext *context;
82
83 GeglRegion *valid_region; /* used when doing unbuffered rendering */
84 GeglRegion *queued_region;
85 GSList *dirty_rectangles;
86 gint chunk_size;
87
88 gdouble progress;
89 };
90
91
G_DEFINE_TYPE(GeglProcessor,gegl_processor,G_TYPE_OBJECT)92 G_DEFINE_TYPE (GeglProcessor, gegl_processor, G_TYPE_OBJECT)
93
94
95 static void
96 gegl_processor_class_init (GeglProcessorClass *klass)
97 {
98 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
99
100 gobject_class->finalize = gegl_processor_finalize;
101 gobject_class->constructed = gegl_processor_constructed;
102 gobject_class->set_property = gegl_processor_set_property;
103 gobject_class->get_property = gegl_processor_get_property;
104
105 g_object_class_install_property (gobject_class, PROP_NODE,
106 g_param_spec_object ("node",
107 "GeglNode",
108 "The GeglNode to process (will saturate the provider's cache if the provided node is a sink node)",
109 GEGL_TYPE_NODE,
110 G_PARAM_WRITABLE |
111 G_PARAM_STATIC_STRINGS |
112 G_PARAM_CONSTRUCT));
113
114 g_object_class_install_property (gobject_class, PROP_RECTANGLE,
115 g_param_spec_pointer ("rectangle",
116 "rectangle",
117 "The rectangle of the region to process.",
118 G_PARAM_READWRITE |
119 G_PARAM_STATIC_STRINGS));
120
121 g_object_class_install_property (gobject_class, PROP_PROGRESS,
122 g_param_spec_double ("progress",
123 "progress",
124 "query progress; 0.0 is not started, 1.0 is done.",
125 0.0, 1.0, 0.0,
126 G_PARAM_READWRITE |
127 G_PARAM_STATIC_STRINGS));
128
129 g_object_class_install_property (gobject_class, PROP_CHUNK_SIZE,
130 g_param_spec_int ("chunksize",
131 "chunksize",
132 "Size of chunks being rendered (larger chunks need more memory to do the processing).",
133 1, 4096 * 4096, gegl_config()->chunk_size,
134 G_PARAM_READWRITE |
135 G_PARAM_STATIC_STRINGS |
136 G_PARAM_CONSTRUCT_ONLY));
137 }
138
139 static void
gegl_processor_init(GeglProcessor * processor)140 gegl_processor_init (GeglProcessor *processor)
141 {
142 processor->level = 0;
143 processor->node = NULL;
144 processor->real_node = NULL;
145 processor->input = NULL;
146 processor->context = NULL;
147 processor->queued_region = NULL;
148 processor->dirty_rectangles = NULL;
149 //processor->chunk_size = 128 * 128;
150 }
151
152 static void
gegl_processor_constructed(GObject * object)153 gegl_processor_constructed (GObject *object)
154 {
155 GeglProcessor *processor = GEGL_PROCESSOR (object);
156
157 G_OBJECT_CLASS (gegl_processor_parent_class)->constructed (object);
158
159 processor->queued_region = gegl_region_new ();
160 }
161
162
163 static void
gegl_processor_finalize(GObject * self_object)164 gegl_processor_finalize (GObject *self_object)
165 {
166 GeglProcessor *processor = GEGL_PROCESSOR (self_object);
167
168 g_clear_pointer (&processor->context, gegl_operation_context_destroy);
169
170 g_clear_object (&processor->node);
171 g_clear_object (&processor->real_node);
172 g_clear_object (&processor->input);
173
174 g_clear_pointer (&processor->queued_region, gegl_region_destroy);
175 g_clear_pointer (&processor->valid_region, gegl_region_destroy);
176
177 G_OBJECT_CLASS (gegl_processor_parent_class)->finalize (self_object);
178 }
179
180 static void
gegl_processor_set_property(GObject * gobject,guint property_id,const GValue * value,GParamSpec * pspec)181 gegl_processor_set_property (GObject *gobject,
182 guint property_id,
183 const GValue *value,
184 GParamSpec *pspec)
185 {
186 GeglProcessor *self = GEGL_PROCESSOR (gobject);
187
188 switch (property_id)
189 {
190 case PROP_NODE:
191 gegl_processor_set_node (self, g_value_get_object (value));
192 break;
193
194 case PROP_CHUNK_SIZE:
195 self->chunk_size = g_value_get_int (value);
196 break;
197
198 case PROP_RECTANGLE:
199 gegl_processor_set_rectangle (self, g_value_get_pointer (value));
200 break;
201
202 default:
203 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
204 break;
205 }
206 }
207
208 static void
gegl_processor_get_property(GObject * gobject,guint property_id,GValue * value,GParamSpec * pspec)209 gegl_processor_get_property (GObject *gobject,
210 guint property_id,
211 GValue *value,
212 GParamSpec *pspec)
213 {
214 GeglProcessor *self = GEGL_PROCESSOR (gobject);
215
216 switch (property_id)
217 {
218 case PROP_NODE:
219 g_value_set_object (value, self->node);
220 break;
221
222 case PROP_RECTANGLE:
223 g_value_set_pointer (value, &self->rectangle);
224 break;
225
226 case PROP_CHUNK_SIZE:
227 g_value_set_int (value, self->chunk_size);
228 break;
229 case PROP_PROGRESS:
230 g_value_set_double (value, gegl_processor_progress (self));
231 break;
232
233 default:
234 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
235 break;
236 }
237 }
238
239 static void
gegl_processor_set_node(GeglProcessor * processor,GeglNode * node)240 gegl_processor_set_node (GeglProcessor *processor,
241 GeglNode *node)
242 {
243 g_return_if_fail (GEGL_IS_NODE (node));
244 g_return_if_fail (node->is_graph || GEGL_IS_OPERATION (node->operation));
245
246 g_set_object (&processor->node, node);
247 g_clear_object (&processor->real_node);
248
249 /* nodes with meta operations are also graphs and can be sinks, so
250 * we don't use their output proxy */
251 if (GEGL_IS_OPERATION (node->operation))
252 processor->real_node = node;
253 else /* ie. node->is_graph */
254 processor->real_node = gegl_node_get_output_proxy (node, "output");
255
256 g_return_if_fail (processor->real_node != NULL);
257 g_object_ref (processor->real_node);
258
259 /* if the processor's node is a sink operation then get the producer node
260 * and set up the region (unless all is going to be needed) */
261 if (processor->real_node->operation &&
262 g_type_is_a (G_OBJECT_TYPE (processor->real_node->operation),
263 GEGL_TYPE_OPERATION_SINK))
264 {
265 processor->input = gegl_node_get_producer (processor->real_node, "input", NULL);
266
267 if (processor->input == NULL)
268 {
269 g_critical ("Prepared to process a sink operation, but it "
270 "had no \"input\" pad connected!");
271 return;
272 }
273
274 if (!gegl_operation_sink_needs_full (processor->real_node->operation))
275 {
276 processor->valid_region = gegl_region_new ();
277 }
278 else
279 {
280 processor->valid_region = NULL;
281 }
282 }
283 /* If the processor's node is not a sink operation, then just use it as
284 * an input, and set the region to NULL */
285 else
286 {
287 processor->input = processor->real_node;
288 processor->valid_region = NULL;
289 }
290
291 g_return_if_fail (processor->input != NULL);
292
293 /* Prepare the graph */
294 gegl_node_get_bounding_box (processor->input);
295
296 g_object_ref (processor->input);
297
298 g_object_notify (G_OBJECT (processor), "node");
299 }
300
301 static void
set_scaled_rectangle(GeglProcessor * processor)302 set_scaled_rectangle (GeglProcessor *processor)
303 {
304 processor->rectangle.x = processor->rectangle_unscaled.x >> processor->level;
305 processor->rectangle.y = processor->rectangle_unscaled.y >> processor->level;
306 processor->rectangle.width = processor->rectangle_unscaled.width >> processor->level;
307 processor->rectangle.height = processor->rectangle_unscaled.height >> processor->level;
308 }
309
310
311 /* Sets the processor->rectangle to the given rectangle (or the node
312 * bounding box if rectangle is NULL) and removes any
313 * dirty_rectangles, then updates node context_id with result rect and
314 * need rect
315 */
316 void
gegl_processor_set_rectangle(GeglProcessor * processor,const GeglRectangle * rectangle)317 gegl_processor_set_rectangle (GeglProcessor *processor,
318 const GeglRectangle *rectangle)
319 {
320 GSList *iter;
321 GeglRectangle input_bounding_box;
322
323 g_return_if_fail (processor->input != NULL);
324
325 if (! rectangle)
326 {
327 input_bounding_box = gegl_node_get_bounding_box (processor->input);
328 rectangle = &input_bounding_box;
329 }
330
331 GEGL_NOTE (GEGL_DEBUG_PROCESS, "gegl_processor_set_rectangle() node = %s rectangle = %d, %d %d×%d",
332 gegl_node_get_debug_name (processor->node),
333 rectangle->x, rectangle->y, rectangle->width, rectangle->height);
334
335 /* if the processor's rectangle isn't already set to the node's bounding box,
336 * then set it and remove processor->dirty_rectangles (set to NULL) */
337 if (! gegl_rectangle_equal (&processor->rectangle_unscaled, rectangle))
338 {
339 #if 0
340 /* XXX: this is a large penalty hit, so we assume the rectangle
341 * we're getting is part of the bounding box we're hitting */
342 GeglRectangle bounds;
343 bounds = processor->bounds;/*gegl_node_get_bounding_box (processor->input);*/
344 #endif
345 processor->rectangle_unscaled = *rectangle;
346 set_scaled_rectangle (processor);
347 #if 0
348 gegl_rectangle_intersect (&processor->rectangle_unscaled, &processor->rectangle_unscaled, &bounds);
349 #endif
350 }
351 {
352
353 /* remove already queued dirty rectangles */
354 for (iter = processor->dirty_rectangles; iter; iter = g_slist_next (iter))
355 {
356 g_slice_free (GeglRectangle, iter->data);
357 }
358 g_slist_free (processor->dirty_rectangles);
359 processor->dirty_rectangles = NULL;
360 }
361
362 /* if the node's operation is a sink and it needs the full content then
363 * a context will be set up together with a cache and
364 * needed and result rectangles */
365 if (processor->real_node &&
366 GEGL_IS_OPERATION_SINK (processor->real_node->operation) &&
367 gegl_operation_sink_needs_full (processor->real_node->operation))
368 {
369 GeglCache *cache;
370
371 cache = gegl_node_get_cache (processor->input);
372
373 if (!processor->context)
374 {
375 processor->context = gegl_operation_context_new (processor->real_node->operation, NULL);
376 }
377
378 gegl_operation_context_set_object (processor->context, "input", G_OBJECT (cache));
379
380 gegl_operation_context_set_result_rect (processor->context,
381 &processor->rectangle_unscaled);
382 gegl_operation_context_set_need_rect (processor->context,
383 &processor->rectangle_unscaled);
384 }
385
386 if (processor->valid_region)
387 {
388 gegl_region_destroy (processor->valid_region);
389 processor->valid_region = gegl_region_new ();
390 }
391
392 g_object_notify (G_OBJECT (processor), "rectangle");
393 }
394
395 /* Will generate band_sizes that are adapted to the size of the tiles */
396 static gint
gegl_processor_get_band_size(gint size)397 gegl_processor_get_band_size (gint size)
398 {
399 gint band_size;
400
401 band_size = size / 2;
402
403 /* try to make the rects generated match better with potential 2^n sized
404 * tiles, XXX: should be improved to make the next slice fit as well. */
405 if (band_size <= 128)
406 {
407 band_size = MIN(band_size, 64); /* prefer a band_size of 128,
408 hoping to hit tiles */
409 }
410 else if (band_size <= 256)
411 {
412 band_size = MIN(band_size, 128); /* prefer a band_size of 128,
413 hoping to hit tiles */
414 }
415 else if (band_size <= 512)
416 {
417 band_size = MIN(band_size, 256); /* prefer a band_size of 128,
418 hoping to hit tiles */
419 }
420
421 if (band_size < 1)
422 band_size = 1;
423
424 return band_size;
425 }
426
427 /* If the processor's dirty rectangle is too big then it will be cut, added
428 * to the processor's list of dirty rectangles and TRUE will be returned.
429 * If the rectangle is small enough it will be processed, using a buffer or
430 * not as appropriate, and will return TRUE if there is more work */
431 static gboolean
render_rectangle(GeglProcessor * processor)432 render_rectangle (GeglProcessor *processor)
433 {
434 gboolean buffered;
435 const gint max_area = processor->chunk_size * (1<<processor->level) * (1<<processor->level) * gegl_config_threads();
436 GeglCache *cache = NULL;
437 const Babl *format = NULL;
438
439 /* Retrieve the cache if the processor's node is not buffered if its
440 * operation is a sink and it doesn't use the full area */
441 buffered = !(GEGL_IS_OPERATION_SINK(processor->real_node->operation) &&
442 !gegl_operation_sink_needs_full (processor->real_node->operation));
443 if (buffered)
444 {
445 cache = gegl_node_get_cache (processor->input);
446 format = gegl_buffer_get_format ((GeglBuffer *)cache);
447 }
448
449 if (processor->dirty_rectangles)
450 {
451 GeglRectangle *dr = processor->dirty_rectangles->data;
452
453 /* If a dirty rectangle is bigger than the max area, then cut it
454 * to smaller pieces */
455 if (dr->height * dr->width > max_area && 1)
456 {
457 gint band_size;
458
459 {
460 GeglRectangle *fragment;
461
462 fragment = g_slice_dup (GeglRectangle, dr);
463
464 /* When splitting a rectangle, we'll do it on the biggest side */
465 if (dr->width > dr->height)
466 {
467 band_size = gegl_processor_get_band_size ( dr->width );
468
469 fragment->width = band_size;
470 dr->width -= band_size;
471 dr->x += band_size;
472 }
473 else
474 {
475 band_size = gegl_processor_get_band_size (dr->height);
476
477 fragment->height = band_size;
478 dr->height -= band_size;
479 dr->y += band_size;
480 }
481 processor->dirty_rectangles = g_slist_prepend (processor->dirty_rectangles, fragment);
482 }
483 return TRUE;
484 }
485 /* remove the rectangle that will be processed from the list of dirty ones */
486 processor->dirty_rectangles = g_slist_remove (processor->dirty_rectangles, dr);
487
488 if (!dr->width || !dr->height)
489 {
490 g_slice_free (GeglRectangle, dr);
491
492 return TRUE;
493 }
494
495 if (buffered)
496 {
497 gboolean found_full = FALSE;
498 for (gint level = processor->level; level >= 0; level--)
499 {
500 if (gegl_region_rect_in (cache->valid_region[level], dr) == GEGL_OVERLAP_RECTANGLE_IN)
501 {
502 found_full = TRUE;
503 break;
504 }
505 /* XXX: dr should be adjusted to be the bounding box of not-found
506 * in cache if there is partial hits
507 */
508 }
509
510 if (!found_full)
511 {
512 /* do the image calculations using the buffer */
513 gegl_node_blit (processor->input, 1.0/(1<<processor->level),
514 dr, format, NULL,
515 GEGL_AUTO_ROWSTRIDE, GEGL_BLIT_CACHE);
516
517 /* tells the cache that the rectangle (dr) has been computed */
518 gegl_cache_computed (cache, dr, processor->level);
519 }
520 g_slice_free (GeglRectangle, dr);
521 }
522 else
523 {
524 gegl_node_blit (processor->real_node, 1.0/(1<<processor->level),
525 dr, NULL, NULL,
526 GEGL_AUTO_ROWSTRIDE, GEGL_BLIT_DEFAULT);
527 gegl_region_union_with_rect (processor->valid_region, dr);
528 g_slice_free (GeglRectangle, dr);
529 }
530 }
531
532 return processor->dirty_rectangles != NULL;
533 }
534
535
536 static gint
rect_area(GeglRectangle * rectangle)537 rect_area (GeglRectangle *rectangle)
538 {
539 return rectangle->width * rectangle->height;
540 }
541
542 /* returns the total area covered by a region */
543 static gint
region_area(GeglRegion * region)544 region_area (GeglRegion *region)
545 {
546 GeglRectangle *rectangles;
547 gint n_rectangles;
548 gint i;
549 gint sum = 0;
550
551 gegl_region_get_rectangles (region, &rectangles, &n_rectangles);
552
553 for (i = 0; i < n_rectangles; i++)
554 {
555 sum += rect_area (&rectangles[i]);
556 }
557 g_free (rectangles);
558
559 return sum;
560 }
561
562 /* returns the area not covered by the rectangle */
563 static gint
area_left(GeglRegion * area,GeglRectangle * rectangle)564 area_left (GeglRegion *area,
565 GeglRectangle *rectangle)
566 {
567 GeglRegion *region;
568 gint sum = 0;
569
570 region = gegl_region_rectangle (rectangle);
571 gegl_region_subtract (region, area);
572 sum += region_area (region);
573 gegl_region_destroy (region);
574 return sum;
575 }
576
577 /* returns true if everything is rendered */
578 static gboolean
gegl_processor_is_rendered(GeglProcessor * processor)579 gegl_processor_is_rendered (GeglProcessor *processor)
580 {
581 if (gegl_region_empty (processor->queued_region) &&
582 processor->dirty_rectangles == NULL)
583 return TRUE;
584 return FALSE;
585 }
586
587 static gdouble
gegl_processor_progress(GeglProcessor * processor)588 gegl_processor_progress (GeglProcessor *processor)
589 {
590 GeglRegion *valid_region;
591 gint valid;
592 gint wanted;
593 gdouble ret;
594
595 g_return_val_if_fail (processor->input != NULL, 1);
596
597 if (processor->valid_region)
598 {
599 valid_region = processor->valid_region;
600 }
601 else
602 {
603 valid_region = gegl_node_get_cache (processor->input)->valid_region[processor->level];
604 }
605
606 wanted = rect_area (&(processor->rectangle));
607 valid = wanted - area_left (valid_region, &(processor->rectangle));
608 if (wanted == 0)
609 {
610 if (gegl_processor_is_rendered (processor))
611 return 1.0;
612 return 0.999;
613 }
614
615 ret = (double) valid / wanted;
616 if (ret>=1.0)
617 {
618 if (!gegl_processor_is_rendered (processor))
619 {
620 return 0.9999;
621 }
622 }
623
624 return ret;
625 }
626
627 /* Processes the rectangle (might be only splitting it to smaller ones) and
628 * updates the progress indicator */
629 static gboolean
gegl_processor_render(GeglProcessor * processor,GeglRectangle * rectangle,gdouble * progress)630 gegl_processor_render (GeglProcessor *processor,
631 GeglRectangle *rectangle,
632 gdouble *progress)
633 {
634 GeglRegion *valid_region;
635
636 if (processor->valid_region)
637 {
638 valid_region = processor->valid_region;
639 }
640 else
641 {
642 g_return_val_if_fail (processor->input != NULL, FALSE);
643 valid_region = gegl_node_get_cache (processor->input)->valid_region[processor->level];
644 }
645
646 {
647 gboolean more_work = render_rectangle (processor);
648
649 if (more_work == TRUE)
650 {
651 if (progress)
652 {
653 gint valid;
654 gint wanted;
655 if (rectangle)
656 {
657 wanted = rect_area (rectangle);
658 valid = wanted - area_left (valid_region, rectangle);
659 }
660 else
661 {
662 valid = region_area (valid_region);
663 wanted = region_area (processor->queued_region);
664 }
665 if (wanted == 0)
666 {
667 *progress = 1.0;
668 }
669 else
670 {
671 *progress = (double) valid / wanted;
672 }
673 }
674
675 return more_work;
676 }
677 }
678
679 if (rectangle)
680 { /* we're asked to work on a specific rectangle thus we only focus
681 on it */
682 GeglRegion *region = gegl_region_rectangle (rectangle);
683 GeglRectangle *rectangles;
684 gint n_rectangles;
685 gint i;
686
687 gegl_region_subtract (region, valid_region);
688 gegl_region_get_rectangles (region, &rectangles, &n_rectangles);
689 gegl_region_destroy (region);
690
691 for (i = 0; i < n_rectangles && i < 1; i++)
692 {
693 GeglRectangle roi = rectangles[i];
694 GeglRegion *tr = gegl_region_rectangle (&roi);
695 gegl_region_subtract (processor->queued_region, tr);
696 gegl_region_destroy (tr);
697
698 processor->dirty_rectangles = g_slist_prepend (processor->dirty_rectangles,
699 g_slice_dup (GeglRectangle, &roi));
700 }
701
702 g_free (rectangles);
703
704 if (n_rectangles != 0)
705 {
706 if (progress)
707 *progress = 1.0 - ((double) area_left (valid_region, rectangle) /
708 rect_area (rectangle));
709 return TRUE;
710 }
711
712 return FALSE;
713 }
714 else if (!gegl_region_empty (processor->queued_region) &&
715 !processor->dirty_rectangles)
716 { /* XXX: this branch of the else can probably be removed if gegl-processors
717 should only work with rectangular queued regions
718 */
719 GeglRectangle *rectangles;
720 gint n_rectangles;
721 gint i;
722
723 gegl_region_get_rectangles (processor->queued_region, &rectangles,
724 &n_rectangles);
725
726 for (i = 0; i < n_rectangles && i < 1; i++)
727 {
728 GeglRectangle roi = rectangles[i];
729 GeglRegion *tr = gegl_region_rectangle (&roi);
730 gegl_region_subtract (processor->queued_region, tr);
731 gegl_region_destroy (tr);
732
733 processor->dirty_rectangles = g_slist_prepend (processor->dirty_rectangles,
734 g_slice_dup (GeglRectangle, &roi));
735 }
736
737 g_free (rectangles);
738 }
739
740 if (progress)
741 {
742 *progress = 0.69;
743 }
744
745 return !gegl_processor_is_rendered (processor);
746 }
747
748 static gboolean
gegl_processor_work_is_opencl_node(GeglNode * node,gpointer data)749 gegl_processor_work_is_opencl_node (GeglNode *node,
750 gpointer data)
751 {
752 return GEGL_OPERATION_GET_CLASS (node->operation)->cl_data ||
753 GEGL_OPERATION_GET_CLASS (node->operation)->opencl_support;
754 }
755
756 /* Will call gegl_processor_render and when there is no more work to be done,
757 * it will write the result to the destination */
758 gboolean
gegl_processor_work(GeglProcessor * processor,gdouble * progress)759 gegl_processor_work (GeglProcessor *processor,
760 gdouble *progress)
761 {
762 gboolean more_work = FALSE;
763
764 if (gegl_config()->use_opencl)
765 {
766 if (gegl_cl_is_accelerated ()
767 && processor->chunk_size != GEGL_CL_CHUNK_SIZE)
768 {
769 GeglVisitor *visitor;
770
771 visitor = gegl_callback_visitor_new (gegl_processor_work_is_opencl_node,
772 NULL);
773
774 if (gegl_visitor_traverse (visitor, GEGL_VISITABLE (processor->real_node)))
775 processor->chunk_size = GEGL_CL_CHUNK_SIZE;
776
777 g_object_unref (visitor);
778 }
779 }
780
781 more_work = gegl_processor_render (processor, &processor->rectangle, progress);
782 if (more_work)
783 {
784 return TRUE;
785 }
786
787 if (progress)
788 {
789 *progress = 1.0;
790 }
791
792 if (processor->context)
793 {
794 /* the actual writing to the destination */
795 gegl_operation_process (processor->real_node->operation,
796 processor->context,
797 "output" /* ignored output_pad */,
798 &processor->context->result_rect, processor->context->level);
799 gegl_operation_context_destroy (processor->context);
800 processor->context = NULL;
801
802 return TRUE;
803 }
804
805 return FALSE;
806 }
807
808 GeglProcessor *
gegl_node_new_processor(GeglNode * node,const GeglRectangle * rectangle)809 gegl_node_new_processor (GeglNode *node,
810 const GeglRectangle *rectangle)
811 {
812 g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
813
814 return g_object_new (GEGL_TYPE_PROCESSOR,
815 "node", node,
816 "rectangle", rectangle,
817 NULL);
818 }
819
gegl_processor_set_level(GeglProcessor * processor,gint level)820 void gegl_processor_set_level (GeglProcessor *processor,
821 gint level)
822 {
823 processor->level = level;
824 set_scaled_rectangle (processor);
825 }
826
gegl_processor_get_buffer(GeglProcessor * processor)827 GeglBuffer *gegl_processor_get_buffer (GeglProcessor *processor)
828 {
829 return processor?GEGL_BUFFER(gegl_node_get_cache (processor->input)):NULL;
830 }
831
832
gegl_processor_set_scale(GeglProcessor * processor,gdouble scale)833 void gegl_processor_set_scale (GeglProcessor *processor,
834 gdouble scale)
835 {
836 processor->level = gegl_level_from_scale (scale);
837 set_scaled_rectangle (processor);
838 }
839