1 #include "config.h"
2 #include <string.h>
3 #include <math.h>
4
5 #include <glib-object.h>
6 #include <glib/gprintf.h>
7
8 #include "gegl-buffer.h"
9 #include "gegl-buffer-formats.h"
10 #include "gegl-buffer-types.h"
11 #include "gegl-rectangle.h"
12 #include "gegl-buffer-private.h"
13 #include "gegl-tile-storage.h"
14 #include "gegl-tile-handler-cache.h"
15
16 GeglBuffer *
gegl_buffer_linear_new(const GeglRectangle * extent,const Babl * format)17 gegl_buffer_linear_new (const GeglRectangle *extent,
18 const Babl *format)
19 {
20 GeglBuffer *buffer;
21
22 if (extent==NULL)
23 {
24 g_error ("got a NULL extent");
25 }
26
27 if (format==NULL)
28 format = gegl_babl_rgba_linear_float ();
29
30 /* creating a linear buffer for GeglBuffer is a matter of
31 * requesting the correct parameters when creating the
32 * buffer
33 */
34 buffer = g_object_new (GEGL_TYPE_BUFFER,
35 "x", extent->x,
36 "y", extent->y,
37 "shift-x", -extent->x,
38 "shift-y", -extent->y,
39 "width", extent->width,
40 "height", extent->height,
41 "tile-width", extent->width,
42 "tile-height", extent->height,
43 "format", format,
44 NULL);
45
46 g_object_set_data (G_OBJECT (buffer), "is-linear", (void*)0xf00);
47
48 return buffer;
49 }
50
51 /* XXX:
52 * this should probably be abstracted into a gegl_buffer_cache_insert_tile */
53 void gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache,
54 GeglTile *tile,
55 gint x,
56 gint y,
57 gint z);
58
59 GeglBuffer *
gegl_buffer_linear_new_from_data(const gpointer data,const Babl * format,const GeglRectangle * extent,gint rowstride,GDestroyNotify destroy_fn,gpointer destroy_fn_data)60 gegl_buffer_linear_new_from_data (const gpointer data,
61 const Babl *format,
62 const GeglRectangle *extent,
63 gint rowstride,
64 GDestroyNotify destroy_fn,
65 gpointer destroy_fn_data)
66 {
67 GeglBuffer *buffer;
68 GeglTile *tile;
69 gint bpp;
70
71 g_return_val_if_fail (extent, NULL);
72 g_return_val_if_fail (format, NULL);
73
74 bpp = babl_format_get_bytes_per_pixel (format);
75
76 if (rowstride == 0)
77 {
78 rowstride = extent->width;
79 }
80 else
81 {
82 g_return_val_if_fail (rowstride > 0, NULL);
83 g_return_val_if_fail (rowstride % bpp == 0, NULL);
84 rowstride = rowstride / bpp;
85 }
86
87 buffer = g_object_new (GEGL_TYPE_BUFFER,
88 "x", extent->x,
89 "y", extent->y,
90 "shift-x", -extent->x,
91 "shift-y", -extent->y,
92 "width", extent->width,
93 "height", extent->height,
94 "tile-width", rowstride,
95 "tile-height", extent->height,
96 "format", format,
97 "path", "RAM",
98 NULL);
99
100 g_object_set_data (G_OBJECT (buffer), "is-linear", (void*)0xf00);
101
102 tile = gegl_tile_new_bare ();
103
104 tile->tile_storage = buffer->tile_storage;
105 tile->x = 0;
106 tile->y = 0;
107 tile->z = 0;
108 tile->rev = tile->stored_rev + 1;
109 tile->keep_identity = TRUE;
110 gegl_tile_set_data_full (tile,
111 (gpointer) data,
112 bpp * rowstride * extent->height,
113 destroy_fn,
114 destroy_fn_data);
115
116 if (buffer->tile_storage->cache)
117 gegl_tile_handler_cache_insert (buffer->tile_storage->cache, tile, 0, 0, 0);
118 gegl_tile_unref (tile);
119
120 return buffer;
121 }
122
123 /* the information kept about a linear buffer, multiple requests can
124 * be handled by the same structure, the multiple clients would have
125 * an immediate shared access to the linear buffer.
126 */
127 typedef struct {
128 gpointer buf;
129 GeglRectangle extent;
130 const Babl *format;
131 gint refs;
132 } BufferInfo;
133
134 /* FIXME: make this use direct data access in more cases than the
135 * case of the base buffer.
136 */
137 gpointer
gegl_buffer_linear_open(GeglBuffer * buffer,const GeglRectangle * extent,gint * rowstride,const Babl * format)138 gegl_buffer_linear_open (GeglBuffer *buffer,
139 const GeglRectangle *extent, /* if NULL, use buf */
140 gint *rowstride,/* returns rowstride */
141 const Babl *format) /* if NULL, from buf */
142 {
143 if (!format)
144 format = buffer->soft_format;
145
146 if (extent == NULL)
147 extent=&buffer->extent;
148
149 /*gegl_buffer_lock (buffer);*/
150 g_rec_mutex_lock (&buffer->tile_storage->mutex);
151 if (extent->x == buffer->extent.x &&
152 extent->y == buffer->extent.y &&
153 extent->width == buffer->tile_width &&
154 extent->height <= buffer->tile_height &&
155 buffer->soft_format == format)
156 {
157 GeglTile *tile;
158
159 g_assert (buffer->tile_width <= buffer->tile_storage->tile_width);
160 g_assert (buffer->tile_height == buffer->tile_storage->tile_height);
161
162 tile = g_object_get_data (G_OBJECT (buffer), "linear-tile");
163 g_assert (tile == NULL); /* We need to reference count returned direct
164 * linear buffers to allow multiple open like
165 * the copying case.
166 */
167 tile = gegl_tile_source_get_tile ((GeglTileSource*) (buffer),
168 0,0,0);
169 g_assert (tile);
170 gegl_tile_lock (tile);
171
172 g_object_set_data (G_OBJECT (buffer), "linear-tile", tile);
173
174 if(rowstride)*rowstride = buffer->tile_storage->tile_width * babl_format_get_bytes_per_pixel (format);
175 return (gpointer)gegl_tile_get_data (tile);
176 }
177 /* first check if there is a linear buffer, share the existing buffer if one
178 * exists.
179 */
180 {
181 GList *linear_buffers;
182 GList *iter;
183 BufferInfo *info = NULL;
184 linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers");
185
186 for (iter = linear_buffers; iter; iter=iter->next)
187 {
188 info = iter->data;
189 if (info->format == format &&
190 info->extent.x == buffer->extent.x &&
191 info->extent.y == buffer->extent.y &&
192 info->extent.width == buffer->extent.width &&
193 info->extent.height == buffer->extent.height
194 )
195 {
196 info->refs++;
197 g_print ("!!!!!! sharing a linear buffer!!!!!\n");
198 return info->buf;
199 }
200 }
201 }
202
203 {
204 BufferInfo *info = g_new0 (BufferInfo, 1);
205 GList *linear_buffers;
206 gint rs;
207 linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers");
208 linear_buffers = g_list_append (linear_buffers, info);
209 g_object_set_data (G_OBJECT (buffer), "linear-buffers", linear_buffers);
210
211 info->extent = *extent;
212 info->format = format;
213
214 rs = info->extent.width * babl_format_get_bytes_per_pixel (format);
215 if(rowstride)*rowstride = rs;
216
217 info->buf = gegl_malloc (rs * info->extent.height);
218 gegl_buffer_get_unlocked (buffer, 1.0, &info->extent, format, info->buf, rs, GEGL_ABYSS_NONE);
219 return info->buf;
220 }
221 return NULL;
222 }
223
224 void
gegl_buffer_linear_close(GeglBuffer * buffer,gpointer linear)225 gegl_buffer_linear_close (GeglBuffer *buffer,
226 gpointer linear)
227 {
228 GeglTile *tile;
229 tile = g_object_get_data (G_OBJECT (buffer), "linear-tile");
230 if (tile)
231 {
232 gegl_tile_unlock (tile);
233 gegl_tile_unref (tile);
234 g_object_set_data (G_OBJECT (buffer), "linear-tile", NULL);
235 }
236 else
237 {
238 GList *linear_buffers;
239 GList *iter;
240 linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers");
241
242 for (iter = linear_buffers; iter; iter=iter->next)
243 {
244 BufferInfo *info = iter->data;
245
246 if (info->buf == linear)
247 {
248 info->refs--;
249
250 if (info->refs>0)
251 {
252 g_print ("EEeeek! %s\n", G_STRLOC);
253 return; /* there are still others holding a reference to
254 * this linear buffer
255 */
256 }
257
258 linear_buffers = g_list_remove (linear_buffers, info);
259 g_object_set_data (G_OBJECT (buffer), "linear-buffers", linear_buffers);
260
261 g_rec_mutex_unlock (&buffer->tile_storage->mutex);
262 /* XXX: potential race */
263 gegl_buffer_set (buffer, &info->extent, 0, info->format, info->buf, 0);
264
265 gegl_free (info->buf);
266 g_free (info);
267
268 g_rec_mutex_lock (&buffer->tile_storage->mutex);
269 break;
270 }
271 }
272 }
273 /*gegl_buffer_unlock (buffer);*/
274 g_rec_mutex_unlock (&buffer->tile_storage->mutex);
275 return;
276 }
277