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