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