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