/* This file is part of GEGL.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see .
*
* Copyright 2006,2007 Øyvind Kolås
*/
#include "config.h"
#include
#include
#include
#include "gegl-buffer.h"
#include "gegl-buffer-private.h"
#include "gegl-tile-handler-empty.h"
G_DEFINE_TYPE (GeglTileHandlerEmpty, gegl_tile_handler_empty,
GEGL_TYPE_TILE_HANDLER)
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);
}
static GeglTile *
get_tile (GeglTileSource *gegl_tile_source,
gint x,
gint y,
gint z)
{
GeglTileSource *source = ((GeglTileHandler *) gegl_tile_source)->source;
GeglTileHandlerEmpty *empty = (GeglTileHandlerEmpty *) gegl_tile_source;
GeglTile *tile = NULL;
if (source)
tile = gegl_tile_source_get_tile (source, x, y, z);
if (tile)
return tile;
if (!empty->tile)
{
gint tile_size = gegl_tile_backend_get_tile_size (empty->backend);
empty->tile = gegl_tile_handler_empty_new_tile (tile_size);
}
tile = gegl_tile_handler_dup_tile (GEGL_TILE_HANDLER (empty),
empty->tile, x, y, z);
/* if empty tiles don't have to be zero-initialized, mark them as fully
* damaged, so that their data is not unnecessarily initialized when
* uncloned.
*
* we currently only do this for level-0 tiles, since it simplifies the rest
* of the code.
*/
if (z == 0 && ! empty->initialized)
tile->damage = ~0ull;
/* no need to store the tile, since we'll just create another empty tile on-
* demand if it's dropped.
*/
gegl_tile_mark_as_stored (tile);
return tile;
}
static gpointer
gegl_tile_handler_empty_command (GeglTileSource *buffer,
GeglTileCommand command,
gint x,
gint y,
gint z,
gpointer data)
{
if (command == GEGL_TILE_GET)
return get_tile (buffer, x, y, z);
return gegl_tile_handler_source_command (buffer, command, x, y, z, data);
}
static void
gegl_tile_handler_empty_class_init (GeglTileHandlerEmptyClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = finalize;
}
static void
gegl_tile_handler_empty_init (GeglTileHandlerEmpty *self)
{
((GeglTileSource *) self)->command = gegl_tile_handler_empty_command;
}
GeglTileHandler *
gegl_tile_handler_empty_new (GeglTileBackend *backend,
gboolean initialized)
{
GeglTileHandlerEmpty *empty = g_object_new (GEGL_TYPE_TILE_HANDLER_EMPTY, NULL);
empty->backend = backend;
empty->tile = NULL;
empty->initialized = initialized;
return (void*)empty;
}
GeglTile *
gegl_tile_handler_empty_new_tile (gint tile_size)
{
static GeglTile *common_tile = NULL;
static const gint common_empty_size = sizeof (gdouble) * 4 * 128 * 128;
GeglTile *tile;
if (tile_size > common_empty_size)
{
/* The tile size is too big to use the shared buffer */
tile = gegl_tile_new (tile_size);
memset (gegl_tile_get_data (tile), 0x00, tile_size);
tile->is_zero_tile = TRUE;
}
else
{
if (!g_atomic_pointer_get (&common_tile) &&
g_once_init_enter (&common_tile))
{
GeglTile *allocated_tile = gegl_tile_new_bare ();
guchar *allocated_buffer = gegl_malloc (common_empty_size);
memset (allocated_buffer, 0x00, common_empty_size);
allocated_tile->data = allocated_buffer;
allocated_tile->destroy_notify = NULL;
allocated_tile->size = common_empty_size;
allocated_tile->is_zero_tile = TRUE;
allocated_tile->is_global_tile = TRUE;
/* avoid counting duplicates of the empty tile towards the total
* cache size, both since this is unnecessary, and since they may
* have different sizes, which is inconsistent with the duplicate-
* tracking cache logic.
*/
(*gegl_tile_n_cached_clones (allocated_tile))++;
g_once_init_leave (&common_tile, allocated_tile);
}
tile = gegl_tile_dup (common_tile);
tile->size = tile_size;
}
return tile;
}