#include "config.h" #include #include #include #include #include "gegl.h" #include "gegl-types-internal.h" #include "gegl-buffer-types.h" #include "gegl-buffer-private.h" #include "gegl-tile-storage.h" #include "gegl-tile-handler-cache.h" #include "gegl-utils.h" static GeglBuffer * gegl_buffer_linear_new2 (const GeglRectangle *extent, const Babl *format, gint rowstride) { if (extent==NULL) { g_error ("got a NULL extent"); } if (format==NULL) format = babl_format ("RGBA float"); if (rowstride <= 0) rowstride = extent->width; /* creating a linear buffer for GeglBuffer is a matter of * requesting the correct parameters when creating the * buffer */ return g_object_new (GEGL_TYPE_BUFFER, "x", extent->x, "y", extent->y, "shift-x", extent->x, "shift-y", extent->y, "width", extent->width, "height", extent->height, "tile-width", rowstride, "tile-height", extent->height, "format", format, NULL); } GeglBuffer * gegl_buffer_linear_new (const GeglRectangle *extent, const Babl *format) { return gegl_buffer_linear_new2 (extent, format, 0); } /* XXX: * this should probably be abstracted into a gegl_buffer_cache_insert_tile */ void gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache, GeglTile *tile, gint x, gint y, gint z); 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) { GeglBuffer *buffer; g_assert (format); if (rowstride <= 0) /* handle both 0 and negative coordinates as a request * for a rowstride, negative rowstrides are not supported. */ rowstride = extent->width; else rowstride = rowstride / babl_format_get_bytes_per_pixel (format); buffer = gegl_buffer_linear_new2 (extent, format, rowstride); { GeglTile *tile = gegl_tile_new_bare (); tile->tile_storage = buffer->tile_storage; tile->x = 0; tile->y = 0; tile->z = 0; tile->next_shared = tile; tile->prev_shared = tile; gegl_tile_set_data_full (tile, (gpointer) data, babl_format_get_bytes_per_pixel (format) * rowstride * extent->height, destroy_fn, destroy_fn_data); if (buffer->tile_storage->cache) gegl_tile_handler_cache_insert (buffer->tile_storage->cache, tile, 0, 0, 0); gegl_tile_unref (tile); } return buffer; } /* the information kept about a linear buffer, multiple requests can * be handled by the same structure, the multiple clients would have * an immediate shared access to the linear buffer. */ typedef struct { gpointer buf; GeglRectangle extent; const Babl *format; gint refs; } BufferInfo; /* FIXME: make this use direct data access in more cases than the * case of the base buffer. */ gpointer * gegl_buffer_linear_open (GeglBuffer *buffer, const GeglRectangle *extent, /* if NULL, use buf */ gint *rowstride,/* returns rowstride */ const Babl *format) /* if NULL, from buf */ { if (!format) format = buffer->soft_format; if (extent == NULL) extent=&buffer->extent; /*gegl_buffer_lock (buffer);*/ g_mutex_lock (buffer->tile_storage->mutex); if (extent->x == buffer->extent.x && extent->y == buffer->extent.y && extent->width == buffer->tile_width && extent->height <= buffer->tile_height && buffer->soft_format == format) { GeglTile *tile; g_assert (buffer->tile_width <= buffer->tile_storage->tile_width); g_assert (buffer->tile_height == buffer->tile_storage->tile_height); tile = g_object_get_data (G_OBJECT (buffer), "linear-tile"); g_assert (tile == NULL); /* We need to reference count returned direct * linear buffers to allow multiple open like * the copying case. */ tile = gegl_tile_source_get_tile ((GeglTileSource*) (buffer), 0,0,0); g_assert (tile); gegl_tile_lock (tile); g_object_set_data (G_OBJECT (buffer), "linear-tile", tile); if(rowstride)*rowstride = buffer->tile_storage->tile_width * babl_format_get_bytes_per_pixel (format); return (gpointer)gegl_tile_get_data (tile); } /* first check if there is a linear buffer, share the existing buffer if one * exists. */ { GList *linear_buffers; GList *iter; BufferInfo *info = NULL; linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers"); for (iter = linear_buffers; iter; iter=iter->next) { info = iter->data; if (info->format == format && info->extent.x == buffer->extent.x && info->extent.y == buffer->extent.y && info->extent.width == buffer->extent.width && info->extent.height == buffer->extent.height ) { info->refs++; g_print ("!!!!!! sharing a linear buffer!!!!!\n"); return info->buf; } } } { BufferInfo *info = g_new0 (BufferInfo, 1); GList *linear_buffers; gint rs; linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers"); linear_buffers = g_list_append (linear_buffers, info); g_object_set_data (G_OBJECT (buffer), "linear-buffers", linear_buffers); info->extent = *extent; info->format = format; rs = info->extent.width * babl_format_get_bytes_per_pixel (format); if(rowstride)*rowstride = rs; info->buf = gegl_malloc (rs * info->extent.height); gegl_buffer_get_unlocked (buffer, 1.0, &info->extent, format, info->buf, rs); return info->buf; } return NULL; } void gegl_buffer_linear_close (GeglBuffer *buffer, gpointer linear) { GeglTile *tile; tile = g_object_get_data (G_OBJECT (buffer), "linear-tile"); if (tile) { gegl_tile_unlock (tile); gegl_tile_unref (tile); g_object_set_data (G_OBJECT (buffer), "linear-tile", NULL); } else { GList *linear_buffers; GList *iter; linear_buffers = g_object_get_data (G_OBJECT (buffer), "linear-buffers"); for (iter = linear_buffers; iter; iter=iter->next) { BufferInfo *info = iter->data; if (info->buf == linear) { info->refs--; if (info->refs>0) { g_print ("EEeeek! %s\n", G_STRLOC); return; /* there are still others holding a reference to * this linear buffer */ } linear_buffers = g_list_remove (linear_buffers, info); g_object_set_data (G_OBJECT (buffer), "linear-buffers", linear_buffers); g_mutex_unlock (buffer->tile_storage->mutex); /* XXX: potential race */ gegl_buffer_set (buffer, &info->extent, 0, info->format, info->buf, 0); gegl_free (info->buf); g_free (info); g_mutex_lock (buffer->tile_storage->mutex); break; } } } /*gegl_buffer_unlock (buffer);*/ g_mutex_unlock (buffer->tile_storage->mutex); return; }