1 /* This file is part of GEGL.
2  *
3  * This library 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  * This library 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 this library; if not, see <https://www.gnu.org/licenses/>.
15  *
16  * Copyright 2006,2007 Øyvind Kolås <pippin@gimp.org>
17  */
18 
19 #include "config.h"
20 
21 #include <string.h>
22 #include <math.h>
23 
24 #include <glib-object.h>
25 
26 #include "gegl-buffer.h"
27 #include "gegl-buffer-types.h"
28 #include "gegl-tile-handler-cache.h"
29 #include "gegl-tile-handler-private.h"
30 #include "gegl-tile-storage.h"
31 #include "gegl-buffer-private.h"
32 
33 struct _GeglTileHandlerPrivate
34 {
35   GeglTileStorage      *tile_storage;
36   GeglTileHandlerCache *cache;
37 };
38 
39 G_DEFINE_TYPE_WITH_PRIVATE (GeglTileHandler, gegl_tile_handler,
40                             GEGL_TYPE_TILE_SOURCE)
41 
42 enum
43 {
44   PROP0,
45   PROP_SOURCE
46 };
47 
48 gboolean gegl_tile_storage_cached_release (GeglTileStorage *storage);
49 
50 static void
gegl_tile_handler_dispose(GObject * object)51 gegl_tile_handler_dispose (GObject *object)
52 {
53   GeglTileHandler *handler = GEGL_TILE_HANDLER (object);
54 
55   if (handler->source)
56     {
57       g_object_unref (handler->source);
58       handler->source = NULL;
59     }
60 
61   G_OBJECT_CLASS (gegl_tile_handler_parent_class)->dispose (object);
62 }
63 
64 static gpointer
gegl_tile_handler_command(GeglTileSource * gegl_tile_source,GeglTileCommand command,gint x,gint y,gint z,gpointer data)65 gegl_tile_handler_command (GeglTileSource *gegl_tile_source,
66                            GeglTileCommand command,
67                            gint            x,
68                            gint            y,
69                            gint            z,
70                            gpointer        data)
71 {
72   GeglTileHandler *handler = (GeglTileHandler*)gegl_tile_source;
73 
74   return gegl_tile_handler_source_command (handler, command, x, y, z, data);
75 }
76 
77 static void
gegl_tile_handler_get_property(GObject * gobject,guint property_id,GValue * value,GParamSpec * pspec)78 gegl_tile_handler_get_property (GObject    *gobject,
79                                 guint       property_id,
80                                 GValue     *value,
81                                 GParamSpec *pspec)
82 {
83   GeglTileHandler *handler = GEGL_TILE_HANDLER (gobject);
84 
85   switch (property_id)
86     {
87       case PROP_SOURCE:
88         g_value_set_object (value, handler->source);
89         break;
90 
91       default:
92         G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
93         break;
94     }
95 }
96 
97 static void
gegl_tile_handler_set_property(GObject * gobject,guint property_id,const GValue * value,GParamSpec * pspec)98 gegl_tile_handler_set_property (GObject      *gobject,
99                                 guint         property_id,
100                                 const GValue *value,
101                                 GParamSpec   *pspec)
102 {
103   GeglTileHandler *handler = GEGL_TILE_HANDLER (gobject);
104 
105   switch (property_id)
106     {
107       case PROP_SOURCE:
108         gegl_tile_handler_set_source (handler, g_value_get_object (value));
109         return;
110 
111       default:
112         G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
113         break;
114     }
115 }
116 
117 static void
gegl_tile_handler_class_init(GeglTileHandlerClass * klass)118 gegl_tile_handler_class_init (GeglTileHandlerClass *klass)
119 {
120   GObjectClass *gobject_class  = G_OBJECT_CLASS (klass);
121 
122   gobject_class->set_property = gegl_tile_handler_set_property;
123   gobject_class->get_property = gegl_tile_handler_get_property;
124   gobject_class->dispose      = gegl_tile_handler_dispose;
125 
126   g_object_class_install_property (gobject_class, PROP_SOURCE,
127                                    g_param_spec_object ("source",
128                                                         "GeglBuffer",
129                                                         "The tilestore to be a facade for",
130                                                         G_TYPE_OBJECT,
131                                                         G_PARAM_READWRITE |
132                                                         G_PARAM_CONSTRUCT |
133                                                         G_PARAM_STATIC_STRINGS));
134 }
135 
136 static void
gegl_tile_handler_init(GeglTileHandler * self)137 gegl_tile_handler_init (GeglTileHandler *self)
138 {
139   ((GeglTileSource *) self)->command = gegl_tile_handler_command;
140 
141   self->priv = gegl_tile_handler_get_instance_private (self);
142 }
143 
144 void
gegl_tile_handler_set_source(GeglTileHandler * handler,GeglTileSource * source)145 gegl_tile_handler_set_source (GeglTileHandler *handler,
146                               GeglTileSource  *source)
147 {
148   if (source != handler->source)
149     {
150       if (handler->source)
151         g_object_unref (handler->source);
152 
153       handler->source = source;
154 
155       if (handler->source)
156         g_object_ref (handler->source);
157     }
158 }
159 
160 void
_gegl_tile_handler_set_tile_storage(GeglTileHandler * handler,GeglTileStorage * tile_storage)161 _gegl_tile_handler_set_tile_storage (GeglTileHandler *handler,
162                                      GeglTileStorage *tile_storage)
163 {
164   handler->priv->tile_storage = tile_storage;
165 }
166 
167 void
_gegl_tile_handler_set_cache(GeglTileHandler * handler,GeglTileHandlerCache * cache)168 _gegl_tile_handler_set_cache (GeglTileHandler      *handler,
169                               GeglTileHandlerCache *cache)
170 {
171   handler->priv->cache = cache;
172 }
173 
174 GeglTileStorage *
_gegl_tile_handler_get_tile_storage(GeglTileHandler * handler)175 _gegl_tile_handler_get_tile_storage (GeglTileHandler *handler)
176 {
177   return handler->priv->tile_storage;
178 }
179 
180 GeglTileHandlerCache *
_gegl_tile_handler_get_cache(GeglTileHandler * handler)181 _gegl_tile_handler_get_cache (GeglTileHandler *handler)
182 {
183   return handler->priv->cache;
184 }
185 
186 GeglTile *
gegl_tile_handler_create_tile(GeglTileHandler * handler,gint x,gint y,gint z)187 gegl_tile_handler_create_tile (GeglTileHandler *handler,
188                                gint             x,
189                                gint             y,
190                                gint             z)
191 {
192   GeglTile *tile;
193 
194   tile = gegl_tile_new (handler->priv->tile_storage->tile_size);
195 
196   tile->tile_storage = handler->priv->tile_storage;
197   tile->x            = x;
198   tile->y            = y;
199   tile->z            = z;
200 
201   if (handler->priv->cache)
202     gegl_tile_handler_cache_insert (handler->priv->cache, tile, x, y, z);
203 
204   return tile;
205 }
206 
207 static GeglTile *
gegl_tile_handler_get_tile_internal(GeglTileHandler * handler,GeglTileSource * source,gint x,gint y,gint z,gboolean preserve_data)208 gegl_tile_handler_get_tile_internal (GeglTileHandler *handler,
209                                      GeglTileSource  *source,
210                                      gint             x,
211                                      gint             y,
212                                      gint             z,
213                                      gboolean         preserve_data)
214 {
215   GeglTile *tile = NULL;
216 
217   if (preserve_data && source)
218     {
219       tile = gegl_tile_source_command (source, GEGL_TILE_GET, x, y, z, NULL);
220     }
221   else if (handler->priv->cache)
222     {
223       tile = gegl_tile_handler_cache_get_tile (handler->priv->cache, x, y, z);
224 
225       if (tile)
226         tile->damage = ~(guint64) 0;
227     }
228 
229   if (! tile)
230     tile = gegl_tile_handler_create_tile (handler, x, y, z);
231 
232   return tile;
233 }
234 
235 GeglTile *
gegl_tile_handler_get_tile(GeglTileHandler * handler,gint x,gint y,gint z,gboolean preserve_data)236 gegl_tile_handler_get_tile (GeglTileHandler *handler,
237                             gint             x,
238                             gint             y,
239                             gint             z,
240                             gboolean         preserve_data)
241 {
242   return gegl_tile_handler_get_tile_internal (handler,
243                                               GEGL_TILE_SOURCE (handler),
244                                               x, y, z,
245                                               preserve_data);
246 }
247 
248 GeglTile *
gegl_tile_handler_get_source_tile(GeglTileHandler * handler,gint x,gint y,gint z,gboolean preserve_data)249 gegl_tile_handler_get_source_tile (GeglTileHandler *handler,
250                                    gint             x,
251                                    gint             y,
252                                    gint             z,
253                                    gboolean         preserve_data)
254 {
255   return gegl_tile_handler_get_tile_internal (handler,
256                                               handler->source,
257                                               x, y, z,
258                                               preserve_data);
259 }
260 
261 GeglTile *
gegl_tile_handler_dup_tile(GeglTileHandler * handler,GeglTile * tile,gint x,gint y,gint z)262 gegl_tile_handler_dup_tile (GeglTileHandler *handler,
263                             GeglTile        *tile,
264                             gint             x,
265                             gint             y,
266                             gint             z)
267 {
268   tile = gegl_tile_dup (tile);
269 
270   tile->x = x;
271   tile->y = y;
272   tile->z = z;
273 
274   if (handler->priv->cache)
275     gegl_tile_handler_cache_insert (handler->priv->cache, tile, x, y, z);
276 
277   return tile;
278 }
279 
280 void
gegl_tile_handler_damage_tile(GeglTileHandler * handler,gint x,gint y,gint z,guint64 damage)281 gegl_tile_handler_damage_tile (GeglTileHandler *handler,
282                                gint             x,
283                                gint             y,
284                                gint             z,
285                                guint64          damage)
286 {
287   GeglTileSource *source;
288 
289   g_return_if_fail (GEGL_IS_TILE_HANDLER (handler));
290 
291   if (z != 0                        ||
292       ! damage                      ||
293       ! handler->priv->tile_storage ||
294       ! handler->priv->tile_storage->seen_zoom)
295     {
296       return;
297     }
298 
299   source = GEGL_TILE_SOURCE (handler);
300 
301   g_rec_mutex_lock (&handler->priv->tile_storage->mutex);
302 
303   while (z < handler->priv->tile_storage->seen_zoom)
304     {
305       guint new_damage;
306       guint mask;
307       gint  i;
308 
309       damage |= damage >> 1;
310       damage |= damage >> 2;
311 
312       new_damage = 0;
313       mask       = 1;
314 
315       for (i = 0; i < 16; i++)
316         {
317           new_damage |= damage & mask;
318           damage >>= 3;
319           mask   <<= 1;
320         }
321 
322       damage = (guint64) new_damage << (32 * (y & 1) + 16 * (x & 1));
323 
324       x >>= 1;
325       y >>= 1;
326       z++;
327 
328       gegl_tile_source_command (source, GEGL_TILE_VOID, x, y, z, &damage);
329     }
330 
331   g_rec_mutex_unlock (&handler->priv->tile_storage->mutex);
332 }
333 
334 void
gegl_tile_handler_damage_rect(GeglTileHandler * handler,const GeglRectangle * rect)335 gegl_tile_handler_damage_rect (GeglTileHandler     *handler,
336                                const GeglRectangle *rect)
337 {
338   GeglTileSource *source;
339   gint            tile_width;
340   gint            tile_height;
341   gint            X1, Y1;
342   gint            X2, Y2;
343   gint            x1, y1;
344   gint            x2, y2;
345   gint            z;
346 
347   g_return_if_fail (GEGL_IS_TILE_HANDLER (handler));
348   g_return_if_fail (rect != NULL);
349 
350   if (! handler->priv->tile_storage            ||
351       ! handler->priv->tile_storage->seen_zoom ||
352       rect->width  <= 0                        ||
353       rect->height <= 0)
354     {
355       return;
356     }
357 
358   source = GEGL_TILE_SOURCE (handler);
359 
360   g_rec_mutex_lock (&handler->priv->tile_storage->mutex);
361 
362   tile_width  = handler->priv->tile_storage->tile_width;
363   tile_height = handler->priv->tile_storage->tile_height;
364 
365   X1 = rect->x;
366   Y1 = rect->y;
367   X2 = rect->x + rect->width  - 1;
368   Y2 = rect->y + rect->height - 1;
369 
370   x1 = floor ((gdouble) X1 / tile_width);
371   y1 = floor ((gdouble) Y1 / tile_height);
372   x2 = floor ((gdouble) X2 / tile_width);
373   y2 = floor ((gdouble) Y2 / tile_height);
374 
375   for (z = 1; z <= handler->priv->tile_storage->seen_zoom; z++)
376     {
377       gint U1, V1;
378       gint U2, V2;
379       gint x,  y;
380 
381       X1 >>= 1;
382       Y1 >>= 1;
383       X2 >>= 1;
384       Y2 >>= 1;
385 
386       x1 >>= 1;
387       y1 >>= 1;
388       x2 >>= 1;
389       y2 >>= 1;
390 
391       U1 = 8 * (X1 - x1 * tile_width)  / tile_width;
392       V1 = 8 * (Y1 - y1 * tile_height) / tile_height;
393       U2 = 8 * (X2 - x2 * tile_width)  / tile_width;
394       V2 = 8 * (Y2 - y2 * tile_height) / tile_height;
395 
396       for (x = x1; x <= x2; x++)
397         {
398           gint  u1 = x == x1 ? U1 : 0;
399           gint  u2 = x == x2 ? U2 : 7;
400           guint base;
401 
402           if (u1 == 0 && u2 == 7)
403             {
404               base = 0x00330033;
405             }
406           else
407             {
408               gint i;
409 
410               base = 0;
411 
412               for (i = u1; i <= u2; i++)
413                 {
414                   base |= 1 << (((i & 1) << 0) |
415                                 ((i & 2) << 1) |
416                                 ((i & 4) << 2));
417                 }
418             }
419 
420           for (y = y1; y <= y2; y++)
421             {
422               gint v1 = y == y1 ? V1 : 0;
423               gint v2 = y == y2 ? V2 : 7;
424 
425               if (u1 + v1 == 0 && u2 + v2 == 14)
426                 {
427                   gegl_tile_source_void (source, x, y, z);
428                 }
429               else
430                 {
431                   guint64 damage = 0;
432                   gint    i;
433 
434                   for (i = v1; i <= v2; i++)
435                     {
436                       damage |= (guint64) base << (((i & 1) << 1) |
437                                                    ((i & 2) << 2) |
438                                                    ((i & 4) << 3));
439                     }
440 
441                   gegl_tile_source_command (source, GEGL_TILE_VOID, x, y, z,
442                                             &damage);
443                 }
444             }
445         }
446     }
447 
448   g_rec_mutex_unlock (&handler->priv->tile_storage->mutex);
449 }
450 
451 void
gegl_tile_handler_lock(GeglTileHandler * handler)452 gegl_tile_handler_lock (GeglTileHandler *handler)
453 {
454   g_return_if_fail (GEGL_IS_TILE_HANDLER (handler));
455 
456   if (handler->priv->tile_storage)
457     g_rec_mutex_lock (&handler->priv->tile_storage->mutex);
458 }
459 
460 void
gegl_tile_handler_unlock(GeglTileHandler * handler)461 gegl_tile_handler_unlock (GeglTileHandler *handler)
462 {
463   g_return_if_fail (GEGL_IS_TILE_HANDLER (handler));
464 
465   if (handler->priv->tile_storage)
466     g_rec_mutex_unlock (&handler->priv->tile_storage->mutex);
467 }
468