Ejemplo n.º 1
0
void
gegl_buffer_iterator_stop (GeglBufferIterator *iter)
{
  int index;
  GeglBufferIteratorPriv *priv = iter->priv;
  priv->state = GeglIteratorState_Invalid;

  for (index = 0; index < priv->num_buffers; index++)
    {
      SubIterState *sub = &priv->sub_iter[index];

      if (sub->current_tile_mode != GeglIteratorTileMode_Empty)
        release_tile (iter, index);

      if (sub->linear_tile)
        {
          if (sub->access_mode & GEGL_ACCESS_WRITE)
            gegl_tile_unlock (sub->linear_tile);
          gegl_tile_unref (sub->linear_tile);
        }

      gegl_buffer_unlock (sub->buffer);

      if (sub->access_mode & GEGL_ACCESS_WRITE)
        gegl_buffer_emit_changed_signal (sub->buffer, &sub->full_rect);
    }

  g_slice_free (GeglBufferIteratorPriv, iter->priv);
  g_slice_free (GeglBufferIterator, iter);
}
Ejemplo n.º 2
0
static void
finalize (GObject *object)
{
  GeglTileHandlerEmpty *empty = GEGL_TILE_HANDLER_EMPTY (object);

  if (empty->tile)
    gegl_tile_unref (empty->tile);

  G_OBJECT_CLASS (gegl_tile_handler_empty_parent_class)->finalize (object);
}
Ejemplo n.º 3
0
void
_gegl_buffer_drop_hot_tile (GeglBuffer *buffer)
{
  GeglTileStorage *storage = buffer->tile_storage;
  if (storage->hot_tile)
    {
      gegl_tile_unref (storage->hot_tile);
      storage->hot_tile = NULL;
    }
}
Ejemplo n.º 4
0
int main(int argc, char **argv)
{
  GeglTile *tile;
  GeglBuffer *buf_a, *buf_b, *buf_small_lin, *buf_big_lin;
  gpointer shared_data = NULL;
  gboolean result = TRUE;
  gpointer scratch_data;
  GeglRectangle buffer_rect = *GEGL_RECTANGLE(0, 0, 128, 128);

  gegl_init (&argc, &argv);

  buf_a = gegl_buffer_new (&buffer_rect, babl_format("RGBA u8"));
  buf_b = gegl_buffer_new (&buffer_rect, babl_format("RGBA u8"));
  buf_small_lin = gegl_buffer_linear_new (&buffer_rect, babl_format("RGBA float"));
  buf_big_lin = gegl_buffer_linear_new (GEGL_RECTANGLE(0, 0, 1024, 1024), babl_format("RGBA float"));

  tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (buf_a), 0, 0, 0);
  shared_data = gegl_tile_get_data(tile);
  gegl_tile_unref (tile);

  if (!assert_is_empty (buf_a, 0, 0, shared_data))
    result = FALSE;
  if (!assert_is_empty (buf_b, 0, 1, shared_data))
    result = FALSE;

  if (!assert_is_empty (buf_a, 0, 0, shared_data))
    result = FALSE;
  if (!assert_is_empty (buf_b, 0, 1, shared_data))
    result = FALSE;

  if (!assert_is_empty (buf_small_lin, 0, 0, shared_data))
    result = FALSE;

  if (!assert_is_unshared (buf_big_lin, 0, 0, shared_data))
    result = FALSE;

  scratch_data = gegl_malloc(4 * buffer_rect.width * buffer_rect.height);
  gegl_buffer_get (buf_a, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE);
  gegl_buffer_get (buf_b, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE);
  gegl_buffer_get (buf_small_lin, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE);
  gegl_buffer_get (buf_big_lin, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE);
  gegl_free (scratch_data);

  g_object_unref(buf_a);
  g_object_unref(buf_b);
  g_object_unref(buf_small_lin);
  g_object_unref(buf_big_lin);

  gegl_exit();

  if (result)
    return SUCCESS;
  return FAILURE;
}
Ejemplo n.º 5
0
static gpointer
gegl_tile_backend_swap_writer_thread (gpointer ignored)
{
  while (TRUE)
    {
      ThreadParams *params;

      g_mutex_lock (&mutex);

      while (g_queue_is_empty (queue) && !exit_thread)
        g_cond_wait (&queue_cond, &mutex);

      if (exit_thread)
        {
          g_mutex_unlock (&mutex);
          GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "exiting writer thread");
          return NULL;
        }

      params = (ThreadParams *)g_queue_pop_head (queue);
      if (params->operation == OP_WRITE)
        {
          in_progress = params;
          params->entry->link = NULL;
        }

      g_mutex_unlock (&mutex);

      switch (params->operation)
        {
        case OP_WRITE:
          gegl_tile_backend_swap_write (params);
          break;
        case OP_TRUNCATE:
          if (ftruncate (out_fd, total) != 0)
            g_warning ("failed to resize swap file: %s", g_strerror (errno));
          break;
        }

      g_mutex_lock (&mutex);

      in_progress = NULL;

      if (params->operation == OP_WRITE)
        gegl_tile_unref (params->tile);

      g_slice_free (ThreadParams, params);

      g_mutex_unlock (&mutex);
    }

  return NULL;
}
Ejemplo n.º 6
0
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_rec_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_rec_mutex_lock (&buffer->tile_storage->mutex);
              break;
            }
        }
    }
  /*gegl_buffer_unlock (buffer);*/
  g_rec_mutex_unlock (&buffer->tile_storage->mutex);
  return;
}
Ejemplo n.º 7
0
static void
release_tile (GeglBufferIterator *iter,
              int index)
{
  GeglBufferIteratorPriv *priv = iter->priv;
  SubIterState           *sub  = &priv->sub_iter[index];

  if (sub->current_tile_mode == GeglIteratorTileMode_DirectTile)
    {
      if (sub->access_mode & GEGL_ACCESS_WRITE)
        gegl_tile_unlock (sub->current_tile);
      gegl_tile_unref (sub->current_tile);

      sub->current_tile = NULL;
      iter->data[index] = NULL;

      sub->current_tile_mode = GeglIteratorTileMode_Empty;
    }
  else if (sub->current_tile_mode == GeglIteratorTileMode_LinearTile)
    {
      sub->current_tile = NULL;
      iter->data[index] = NULL;

      sub->current_tile_mode = GeglIteratorTileMode_Empty;
    }
  else if (sub->current_tile_mode == GeglIteratorTileMode_GetBuffer)
    {
      if (sub->access_mode & GEGL_ACCESS_WRITE)
        {
          gegl_buffer_set_unlocked_no_notify (sub->buffer,
                                              &sub->real_roi,
                                              sub->level,
                                              sub->format,
                                              sub->real_data,
                                              GEGL_AUTO_ROWSTRIDE);
        }

      gegl_free (sub->real_data);
      sub->real_data = NULL;
      iter->data[index] = NULL;

      sub->current_tile_mode = GeglIteratorTileMode_Empty;
    }
  else if (sub->current_tile_mode == GeglIteratorTileMode_Empty)
    {
      return;
    }
  else
    {
      g_warn_if_reached ();
    }
}
Ejemplo n.º 8
0
static void
gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self,
                                    SwapEntry           *entry,
                                    GeglTile            *tile)
{
  ThreadParams *params;
  gint          length = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));

  gegl_tile_backend_swap_ensure_exist ();

  if (entry->link)
    {
      g_mutex_lock (&mutex);

      if (entry->link)
        {
          params = entry->link->data;
          gegl_tile_unref (params->tile);
          params->tile = gegl_tile_dup (tile);
          g_mutex_unlock (&mutex);

          GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "tile %i, %i, %i at %i is already enqueued, changed data", entry->x, entry->y, entry->z, (gint)entry->offset);

          return;
        }

      g_mutex_unlock (&mutex);
    }

  params            = g_slice_new0 (ThreadParams);
  params->operation = OP_WRITE;
  params->length    = length;
  params->tile      = gegl_tile_dup (tile);
  params->entry     = entry;

  gegl_tile_backend_swap_push_queue (params);

  GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "pushed write of entry %i, %i, %i at %i", entry->x, entry->y, entry->z, (gint)entry->offset);
}
Ejemplo n.º 9
0
static gboolean
assert_is_empty (GeglBuffer *buf,
                 gint        x,
                 gint        y,
                 gpointer    shared_data)
{
  gboolean  result = TRUE;
  GeglTile *tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (buf), x, y, 0);

  if (!tile->is_zero_tile)
    {
      g_warning ("Not a zero tile");
      result = FALSE;
    }
  if (gegl_tile_get_data(tile) != shared_data)
    {
      g_warning ("Not using shared data");
      result = FALSE;
    }

  gegl_tile_unref (tile);

  return result;
}
Ejemplo n.º 10
0
GeglBuffer *
gegl_buffer_load (const gchar *path)
{
  GeglBuffer *ret;

  LoadInfo *info = g_slice_new0 (LoadInfo);

  info->path = g_strdup (path);
  info->i = g_open (info->path, O_RDONLY, 0770);
  GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "starting to load buffer %s", path);
  if (info->i == -1)
    {
      GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "failed top open %s for reading", path);
      return NULL;
    }

  {
    GeglBufferItem *header = gegl_buffer_read_header (info->i, &info->offset);
    g_assert (header);
    /*memcpy (&(info->header), header, sizeof (GeglBufferHeader));*/
    info->header = *(&header->header);
    info->offset = info->header.next;
    /*g_free (header);*/  /* is there a pointer to a string or something we're missing? */
  }



  info->tile_size    = info->header.tile_width *
                       info->header.tile_height *
                       info->header.bytes_per_pixel;
  info->format       = babl_format (info->header.description);

  ret = g_object_new (GEGL_TYPE_BUFFER,
                      "format", info->format,
                      "tile-width", info->header.tile_width,
                      "tile-height", info->header.tile_height,
                      "height", info->header.height,
                      "width", info->header.width,
                      "path", path,
                      NULL);

  /* sanity check, should probably report error condition and return safely instead
  */
  g_assert (babl_format_get_bytes_per_pixel (info->format) == info->header.bytes_per_pixel);

  info->tiles = gegl_buffer_read_index (info->i, &info->offset);

  /* load each tile */
  {
    GList *iter;
    gint   i = 0;
    for (iter = info->tiles; iter; iter = iter->next)
      {
        GeglBufferTile *entry = iter->data;
        guchar         *data;
        GeglTile       *tile;


        tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (ret),
                                          entry->x,
                                          entry->y,
                                          entry->z);

        if (info->offset != entry->offset)
          {
            seekto (info, entry->offset);
          }
        /*g_assert (info->offset == entry->offset);*/


        g_assert (tile);
        gegl_tile_lock (tile);

        data = gegl_tile_get_data (tile);
        g_assert (data);

        {
          ssize_t sz_read = read (info->i, data, info->tile_size);
          if(sz_read != -1)
            info->offset += sz_read;
        }
        /*g_assert (info->offset == entry->offset + info->tile_size);*/

        gegl_tile_unlock (tile);
        gegl_tile_unref (tile);
        i++;
      }
    GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "%i tiles loaded",i);
  }
  GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "buffer loaded %s", info->path);

  load_info_destroy (info);
  return ret;
}
Ejemplo n.º 11
0
static GeglTile *
get_tile (GeglTileSource *gegl_tile_source,
          gint            x,
          gint            y,
          gint            z)
{
  GeglTileSource      *source = ((GeglTileHandler *) gegl_tile_source)->source;
  GeglTileHandlerZoom *zoom   = (GeglTileHandlerZoom *) gegl_tile_source;
  GeglTile            *tile   = NULL;
  const Babl          *format = gegl_tile_backend_get_format (zoom->backend);
  GeglTileStorage     *tile_storage;
  gint                 tile_width;
  gint                 tile_height;
  gint                 tile_size;

  if (source)
    tile = gegl_tile_source_get_tile (source, x, y, z);

  if (tile)
    return tile;

  if (z == 0)/* at base level with no tile found->send null, and shared empty
               tile will be used instead */
    {
      return NULL;
    }

  tile_storage = _gegl_tile_handler_get_tile_storage ((GeglTileHandler *) zoom);

  if (z > tile_storage->seen_zoom)
    tile_storage->seen_zoom = z;

  g_object_get (zoom->backend,
                "tile-width", &tile_width,
                "tile-height", &tile_height,
                "tile-size", &tile_size,
                NULL);

  {
    gint      i, j;
    GeglTile *source_tile[2][2] = { { NULL, NULL }, { NULL, NULL } };

    for (i = 0; i < 2; i++)
      for (j = 0; j < 2; j++)
        {
          /* we get the tile from ourselves, to make successive rescales work
           * correctly */
            source_tile[i][j] = gegl_tile_source_get_tile (gegl_tile_source,
                                                          x * 2 + i, y * 2 + j, z - 1);
        }

    if (source_tile[0][0] == NULL &&
        source_tile[0][1] == NULL &&
        source_tile[1][0] == NULL &&
        source_tile[1][1] == NULL)
      {
        return NULL;   /* no data from level below, return NULL and let GeglTileHandlerEmpty
                          fill in the shared empty tile */
      }

    g_assert (tile == NULL);

    tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (zoom), x, y, z);

    gegl_tile_lock (tile);

    for (i = 0; i < 2; i++)
      for (j = 0; j < 2; j++)
        {
          if (source_tile[i][j])
            {
              set_half (tile, source_tile[i][j], tile_width, tile_height, format, i, j);
              gegl_tile_unref (source_tile[i][j]);
            }
          else
            {
              set_blank (tile, tile_width, tile_height, format, i, j);
            }
        }
    gegl_tile_unlock (tile);
  }

  return tile;
}
Ejemplo n.º 12
0
static void
gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
                                      SwapEntry           *entry)
{
  guint64  start, end;
  gint     tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
  GList   *hlink;

  if (entry->link)
    {
      GList *link;

      g_mutex_lock (&mutex);

      if ((link = entry->link))
        {
          ThreadParams *queued_op = link->data;
          g_queue_delete_link (queue, link);
          gegl_tile_unref (queued_op->tile);
          g_slice_free (ThreadParams, queued_op);
        }

      g_mutex_unlock (&mutex);
    }

  start = entry->offset;
  end = start + tile_size;

  if ((hlink = gap_list))
    while (hlink)
      {
        GList *llink = hlink->prev;
        SwapGap *lgap, *hgap;

        if (llink)
          lgap = llink->data;

        hgap = hlink->data;

        /* attempt to merge lower, upper and this gap */
        if (llink != NULL && lgap->end == start &&
            hgap->start == end)
          {
            llink->next = hlink->next;
            if (hlink->next)
              hlink->next->prev = llink;
            lgap->end = hgap->end;

            g_slice_free (SwapGap, hgap);
            hlink->next = NULL;
            hlink->prev = NULL;
            g_list_free (hlink);
            break;
          }
        /* attempt to merge with upper gap */
        else if (hgap->start == end)
          {
            hgap->start = start;
            break;
          }
        /* attempt to merge with lower gap */
        else if (llink != NULL && lgap->end == start)
          {
            lgap->end = end;
            break;
          }
        /* create new gap */
        else if (hgap->start > end)
          {
            lgap = gegl_tile_backend_swap_gap_new (start, end);
            gap_list = g_list_insert_before (gap_list, hlink, lgap);
            break;
          }

        /* if there's no more elements in the list after this */
        else if (hlink->next == NULL)
          {
            /* attempt to merge with the last gap */
            if (hgap->end == start)
              {
                hgap->end = end;
              }
            /* create a new gap in the end of the list */
            else
              {
                GList *new_link;
                hgap = gegl_tile_backend_swap_gap_new (start, end);
                new_link = g_list_alloc ();
                new_link->next = NULL;
                new_link->prev = hlink;
                new_link->data = hgap;
                hlink->next = new_link;
              }
            break;
          }

        hlink = hlink->next;
      }
  else
    gap_list = g_list_prepend (NULL,
                               gegl_tile_backend_swap_gap_new (start, end));

  g_hash_table_remove (self->index, entry);
  g_slice_free (SwapEntry, entry);
}
Ejemplo n.º 13
0
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;
  GeglTile   *tile;
  gint        bpp;

  g_return_val_if_fail (extent, NULL);
  g_return_val_if_fail (format, NULL);

  bpp = babl_format_get_bytes_per_pixel (format);

  if (rowstride == 0)
    {
      rowstride = extent->width;
    }
  else
    {
      g_return_val_if_fail (rowstride > 0, NULL);
      g_return_val_if_fail (rowstride % bpp == 0, NULL);
      rowstride = rowstride / bpp;
    }

  buffer = 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,
                         "path", "RAM",
                         NULL);

  g_object_set_data (G_OBJECT (buffer), "is-linear", (void*)0xf00);

  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;
  tile->rev = tile->stored_rev + 1;
  gegl_tile_set_data_full (tile,
                           (gpointer) data,
                           bpp * 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;
}
static gboolean
gegl_buffer_tile_iterator_next (GeglBufferTileIterator *i)
{
  GeglBuffer *buffer   = i->buffer;
  gint  tile_width     = buffer->tile_storage->tile_width;
  gint  tile_height    = buffer->tile_storage->tile_height;
  gint  buffer_shift_x = buffer->shift_x;
  gint  buffer_shift_y = buffer->shift_y;
  gint  buffer_x       = i->roi.x + buffer_shift_x;
  gint  buffer_y       = i->roi.y + buffer_shift_y;

  if (i->roi.width == 0 || i->roi.height == 0)
    return FALSE;

gulp:

  /* unref previously held tile */
  if (i->tile)
    {
      if (i->write && i->subrect.width == tile_width && i->same_format)
        {
          gegl_tile_unlock (i->tile);
        }
      gegl_tile_unref (i->tile);
      i->tile = NULL;
    }

  if (i->next_col < i->roi.width)
    { /* return tile on this row */
      gint tiledx = buffer_x + i->next_col;
      gint tiledy = buffer_y + i->next_row;
      gint offsetx = gegl_tile_offset (tiledx, tile_width);
      gint offsety = gegl_tile_offset (tiledy, tile_height);

        {
         i->subrect.x = offsetx;
         i->subrect.y = offsety;
         if (i->roi.width + offsetx - i->next_col < tile_width)
           i->subrect.width = (i->roi.width + offsetx - i->next_col) - offsetx;
         else
           i->subrect.width = tile_width - offsetx;

         if (i->roi.height + offsety - i->next_row < tile_height)
           i->subrect.height = (i->roi.height + offsety - i->next_row) - offsety;
         else
           i->subrect.height = tile_height - offsety;

         i->tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
                                        gegl_tile_indice (tiledx, tile_width),
                                        gegl_tile_indice (tiledy, tile_height),
                                        0);
         if (i->write && i->subrect.width == tile_width && i->same_format)
           {
             gegl_tile_lock (i->tile);
           }
         i->data = gegl_tile_get_data (i->tile);

         {
         gint bpp = babl_format_get_bytes_per_pixel (i->buffer->soft_format);
         i->rowstride = bpp * tile_width;
         i->sub_data = (guchar*)(i->data) + bpp * 
                        (i->subrect.y * tile_width + i->subrect.x);
         }

         i->col = i->next_col;
         i->row = i->next_row;
         i->next_col += tile_width - offsetx;


         i->roi2.x      = i->roi.x + i->col;
         i->roi2.y      = i->roi.y + i->row;
         i->roi2.width  = i->subrect.width;
         i->roi2.height = i->subrect.height;

         return TRUE;
       }
    }
  else /* move down to next row */
    {
      gint tiledy;
      gint offsety;

      i->row = i->next_row;
      i->col = i->next_col;

      tiledy = buffer_y + i->next_row;
      offsety = gegl_tile_offset (tiledy, tile_height);

      i->next_row += tile_height - offsety;
      i->next_col=0;

      if (i->next_row < i->roi.height)
        {
          goto gulp; /* return the first tile in the next row */
        }
      return FALSE;
    }
  return FALSE;
}
Ejemplo n.º 15
0
static void inline
gegl_sampler_get_pixel (GeglSampler    *sampler,
                        gint            x,
                        gint            y,
                        gpointer        data,
                        GeglAbyssPolicy repeat_mode)
{
  GeglSamplerNearest *nearest_sampler = (GeglSamplerNearest*)(sampler);
  GeglBuffer *buffer = sampler->buffer;
  const GeglRectangle *abyss = &buffer->abyss;
  guchar              *buf   = data;

  if (y <  abyss->y ||
      x <  abyss->x ||
      y >= abyss->y + abyss->height ||
      x >= abyss->x + abyss->width)
    {
      switch (repeat_mode)
      {
        case GEGL_ABYSS_CLAMP:
          x = CLAMP (x, abyss->x, abyss->x+abyss->width-1);
          y = CLAMP (y, abyss->y, abyss->y+abyss->height-1);
          break;

        case GEGL_ABYSS_LOOP:
          x = abyss->x + GEGL_REMAINDER (x - abyss->x, abyss->width);
          y = abyss->y + GEGL_REMAINDER (y - abyss->y, abyss->height);
          break;

        case GEGL_ABYSS_BLACK:
          {
            gfloat color[4] = {0.0, 0.0, 0.0, 1.0};
            babl_process (babl_fish (gegl_babl_rgba_linear_float (), sampler->format),
                          color,
                          buf,
                          1);
            return;
          }

        case GEGL_ABYSS_WHITE:
          {
            gfloat color[4] = {1.0, 1.0, 1.0, 1.0};
            babl_process (babl_fish (gegl_babl_rgba_linear_float (),
                                     sampler->format),
                          color,
                          buf,
                          1);
            return;
          }

        default:
        case GEGL_ABYSS_NONE:
          memset (buf, 0x00, babl_format_get_bytes_per_pixel (sampler->format));
          return;
      }
    }

  gegl_buffer_lock (sampler->buffer);

  {
    gint tile_width  = buffer->tile_width;
    gint tile_height = buffer->tile_height;
    gint tiledy      = y + buffer->shift_y;
    gint tiledx      = x + buffer->shift_x;
    gint indice_x    = gegl_tile_indice (tiledx, tile_width);
    gint indice_y    = gegl_tile_indice (tiledy, tile_height);

    GeglTile *tile = nearest_sampler->hot_tile;

    if (!(tile &&
          tile->x == indice_x &&
          tile->y == indice_y))
      {
        if (gegl_config_threads()>1)
          g_rec_mutex_lock (&buffer->tile_storage->mutex);

        if (tile)
          gegl_tile_unref (tile);

        tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
                                          indice_x, indice_y,
                                          0);
        nearest_sampler->hot_tile = tile;

        if (gegl_config_threads()>1)
          g_rec_mutex_unlock (&buffer->tile_storage->mutex);
      }

    if (tile)
      {
        gint tile_origin_x = indice_x * tile_width;
        gint tile_origin_y = indice_y * tile_height;
        gint       offsetx = tiledx - tile_origin_x;
        gint       offsety = tiledy - tile_origin_y;

        guchar *tp = gegl_tile_get_data (tile) + (offsety * tile_width + offsetx) * nearest_sampler->buffer_bpp;

        babl_process (sampler->fish, tp, buf, 1);
      }
  }

  gegl_buffer_unlock (sampler->buffer);
}