Blame gegl/buffer/gegl-buffer-linear.c

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