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 #include "config.h"
19 #include <glib.h>
20 #include <glib-object.h>
21 #include <string.h>
22
23 #include "gegl-buffer.h"
24 #include "gegl-buffer-private.h"
25 #include "gegl-tile-handler-empty.h"
26
G_DEFINE_TYPE(GeglTileHandlerEmpty,gegl_tile_handler_empty,GEGL_TYPE_TILE_HANDLER)27 G_DEFINE_TYPE (GeglTileHandlerEmpty, gegl_tile_handler_empty,
28 GEGL_TYPE_TILE_HANDLER)
29
30 static void
31 finalize (GObject *object)
32 {
33 GeglTileHandlerEmpty *empty = GEGL_TILE_HANDLER_EMPTY (object);
34
35 if (empty->tile)
36 gegl_tile_unref (empty->tile);
37
38 G_OBJECT_CLASS (gegl_tile_handler_empty_parent_class)->finalize (object);
39 }
40
41 static GeglTile *
get_tile(GeglTileSource * gegl_tile_source,gint x,gint y,gint z)42 get_tile (GeglTileSource *gegl_tile_source,
43 gint x,
44 gint y,
45 gint z)
46 {
47 GeglTileSource *source = ((GeglTileHandler *) gegl_tile_source)->source;
48 GeglTileHandlerEmpty *empty = (GeglTileHandlerEmpty *) gegl_tile_source;
49 GeglTile *tile = NULL;
50
51 if (source)
52 tile = gegl_tile_source_get_tile (source, x, y, z);
53 if (tile)
54 return tile;
55
56 if (!empty->tile)
57 {
58 gint tile_size = gegl_tile_backend_get_tile_size (empty->backend);
59 empty->tile = gegl_tile_handler_empty_new_tile (tile_size);
60 }
61
62 tile = gegl_tile_handler_dup_tile (GEGL_TILE_HANDLER (empty),
63 empty->tile, x, y, z);
64
65 /* if empty tiles don't have to be zero-initialized, mark them as fully
66 * damaged, so that their data is not unnecessarily initialized when
67 * uncloned.
68 *
69 * we currently only do this for level-0 tiles, since it simplifies the rest
70 * of the code.
71 */
72 if (z == 0 && ! empty->initialized)
73 tile->damage = ~0ull;
74
75 /* no need to store the tile, since we'll just create another empty tile on-
76 * demand if it's dropped.
77 */
78 gegl_tile_mark_as_stored (tile);
79
80 return tile;
81 }
82
83 static gpointer
gegl_tile_handler_empty_command(GeglTileSource * buffer,GeglTileCommand command,gint x,gint y,gint z,gpointer data)84 gegl_tile_handler_empty_command (GeglTileSource *buffer,
85 GeglTileCommand command,
86 gint x,
87 gint y,
88 gint z,
89 gpointer data)
90 {
91 if (command == GEGL_TILE_GET)
92 return get_tile (buffer, x, y, z);
93
94 return gegl_tile_handler_source_command (buffer, command, x, y, z, data);
95 }
96
97 static void
gegl_tile_handler_empty_class_init(GeglTileHandlerEmptyClass * klass)98 gegl_tile_handler_empty_class_init (GeglTileHandlerEmptyClass *klass)
99 {
100 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
101
102 gobject_class->finalize = finalize;
103 }
104
105 static void
gegl_tile_handler_empty_init(GeglTileHandlerEmpty * self)106 gegl_tile_handler_empty_init (GeglTileHandlerEmpty *self)
107 {
108 ((GeglTileSource *) self)->command = gegl_tile_handler_empty_command;
109 }
110
111 GeglTileHandler *
gegl_tile_handler_empty_new(GeglTileBackend * backend,gboolean initialized)112 gegl_tile_handler_empty_new (GeglTileBackend *backend,
113 gboolean initialized)
114 {
115 GeglTileHandlerEmpty *empty = g_object_new (GEGL_TYPE_TILE_HANDLER_EMPTY, NULL);
116
117 empty->backend = backend;
118 empty->tile = NULL;
119 empty->initialized = initialized;
120
121 return (void*)empty;
122 }
123
124 GeglTile *
gegl_tile_handler_empty_new_tile(gint tile_size)125 gegl_tile_handler_empty_new_tile (gint tile_size)
126 {
127 static GeglTile *common_tile = NULL;
128 static const gint common_empty_size = sizeof (gdouble) * 4 * 128 * 128;
129
130 GeglTile *tile;
131
132 if (tile_size > common_empty_size)
133 {
134 /* The tile size is too big to use the shared buffer */
135 tile = gegl_tile_new (tile_size);
136
137 memset (gegl_tile_get_data (tile), 0x00, tile_size);
138 tile->is_zero_tile = TRUE;
139 }
140 else
141 {
142 if (!g_atomic_pointer_get (&common_tile) &&
143 g_once_init_enter (&common_tile))
144 {
145 GeglTile *allocated_tile = gegl_tile_new_bare ();
146 guchar *allocated_buffer = gegl_malloc (common_empty_size);
147 memset (allocated_buffer, 0x00, common_empty_size);
148
149 allocated_tile->data = allocated_buffer;
150 allocated_tile->destroy_notify = NULL;
151 allocated_tile->size = common_empty_size;
152 allocated_tile->is_zero_tile = TRUE;
153 allocated_tile->is_global_tile = TRUE;
154
155 /* avoid counting duplicates of the empty tile towards the total
156 * cache size, both since this is unnecessary, and since they may
157 * have different sizes, which is inconsistent with the duplicate-
158 * tracking cache logic.
159 */
160 (*gegl_tile_n_cached_clones (allocated_tile))++;
161
162 g_once_init_leave (&common_tile, allocated_tile);
163 }
164
165 tile = gegl_tile_dup (common_tile);
166
167 tile->size = tile_size;
168 }
169
170 return tile;
171 }
172