app: GeglBuffer tile backend - add ability to combine tiles

Add ability to combine tiles, this removes the zero copy case, but permits
using only a single buffer as the view on the tiles.

For the projection (or any othe tiles that have a invalidate_proc set, the
old code paths and 1x1 tiles are used - (including 0 copy for now - but always
requesting write access for the tiles.)
This commit is contained in:
Øyvind Kolås 2012-03-20 17:36:14 +00:00 committed by Michael Natterer
parent 1a1fd29982
commit ec3dc3870f
1 changed files with 231 additions and 60 deletions

View File

@ -2,7 +2,8 @@
* Copyright (C) 1995 Spencer Kimball and Peter Mattis * Copyright (C) 1995 Spencer Kimball and Peter Mattis
* *
* gimptilebackendtilemanager.c * gimptilebackendtilemanager.c
* Copyright (C) 2011 Øyvind Kolås <pippin@gimp.org> * Copyright (C) 2011,2012 Øyvind Kolås <pippin@gimp.org>
* 2011 Martin Nordholts
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,6 +21,7 @@
#include "config.h" #include "config.h"
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <gegl.h> #include <gegl.h>
@ -32,6 +34,7 @@
#include "base/tile.h" #include "base/tile.h"
#include "base/tile-manager.h" #include "base/tile-manager.h"
#include "base/tile-manager-private.h"
#include "gimptilebackendtilemanager.h" #include "gimptilebackendtilemanager.h"
#include "gimp-gegl-utils.h" #include "gimp-gegl-utils.h"
@ -41,8 +44,49 @@ struct _GimpTileBackendTileManagerPrivate
{ {
TileManager *tile_manager; TileManager *tile_manager;
int write; int write;
int mul;
}; };
static int gimp_gegl_tile_mul (void)
{
// gegl projection
// 8 - 18.6
// 4 - 15.09
// 2 - 16.09
// 1 - 21.5 <---------
//------
// legacy projection
// 1 - 18.6 <---------
// 2 - 15.07
// 4 - 15.8
// 8 - 18.1
//
// ---------------------------------------- projection 0copy
// 1 - 21.15
// 2 - 17.6
// 4 - 14.9
// 8 - 17.036
// ---------------------------------------- 2d, with projection 0copy
//10 - 14.1
// 9 - 15.11
// 8 - 18.11 \ 15.2
// 7 - 16
// 6 - 14.11
// 4 - 16.8
// 3 - 17.8
// 2 - 16.1
static int mul = 8;
static gboolean inited = 0;
if (G_LIKELY (inited))
return mul;
inited = 1;
if (g_getenv ("GIMP_GEGL_TILE_MUL"))
mul = atoi (g_getenv ("GIMP_GEGL_TILE_MUL"));
if (mul < 1)
mul = 1;
return mul;
}
static void gimp_tile_backend_tile_manager_finalize (GObject *object); static void gimp_tile_backend_tile_manager_finalize (GObject *object);
@ -54,12 +98,24 @@ static gpointer gimp_tile_backend_tile_manager_command (GeglTileSource *tile_s
gint z, gint z,
gpointer data); gpointer data);
static void gimp_tile_write (GimpTileBackendTileManager *ram, static void gimp_tile_write (GimpTileBackendTileManager *backend_tm,
gint x, gint x,
gint y, gint y,
gint z,
guchar *source); guchar *source);
static GeglTile * gimp_tile_read (GimpTileBackendTileManager *backend_tm,
gint x,
gint y);
static void gimp_tile_write_mul (GimpTileBackendTileManager *backend_tm,
gint x,
gint y,
guchar *source);
static GeglTile * gimp_tile_read_mul (GimpTileBackendTileManager *backend_tm,
gint x,
gint y);
G_DEFINE_TYPE (GimpTileBackendTileManager, gimp_tile_backend_tile_manager, G_DEFINE_TYPE (GimpTileBackendTileManager, gimp_tile_backend_tile_manager,
GEGL_TYPE_TILE_BACKEND) GEGL_TYPE_TILE_BACKEND)
@ -131,68 +187,28 @@ gimp_tile_backend_tile_manager_command (GeglTileSource *tile_store,
gpointer data) gpointer data)
{ {
GimpTileBackendTileManager *backend_tm; GimpTileBackendTileManager *backend_tm;
GeglTileBackend *backend;
backend_tm = GIMP_TILE_BACKEND_TILE_MANAGER (tile_store); backend_tm = GIMP_TILE_BACKEND_TILE_MANAGER (tile_store);
backend = GEGL_TILE_BACKEND (tile_store);
switch (command) switch (command)
{ {
case GEGL_TILE_GET: case GEGL_TILE_GET:
{ if (backend_tm->priv->mul > 1)
GeglTile *tile; return gimp_tile_read_mul (backend_tm, x, y);
gint tile_size; return gimp_tile_read (backend_tm, x, y);
Tile *gimp_tile;
gint tile_stride;
gint gimp_tile_stride;
int row;
gimp_tile = tile_manager_get_at (backend_tm->priv->tile_manager,
x, y, TRUE, backend_tm->priv->write);
if (!gimp_tile)
return NULL;
g_return_val_if_fail (gimp_tile != NULL, NULL);
tile_size = gegl_tile_backend_get_tile_size (backend);
tile_stride = TILE_WIDTH * tile_bpp (gimp_tile);
gimp_tile_stride = tile_ewidth (gimp_tile) * tile_bpp (gimp_tile);
if (tile_stride == gimp_tile_stride &&
TILE_HEIGHT == tile_eheight (gimp_tile))
{
/* use the GimpTile directly as GEGL tile */
tile = gegl_tile_new_bare ();
gegl_tile_set_data_full (tile, tile_data_pointer (gimp_tile, 0, 0),
tile_size,
backend_tm->priv->write?
tile_done_writing:tile_done,
gimp_tile);
}
else
{
/* create a copy of the tile */
tile = gegl_tile_new (tile_size);
for (row = 0; row < tile_eheight (gimp_tile); row++)
{
memcpy (gegl_tile_get_data (tile) + row * tile_stride,
tile_data_pointer (gimp_tile, 0, row),
gimp_tile_stride);
}
tile_release (gimp_tile, backend_tm->priv->write);
}
return tile;
}
case GEGL_TILE_SET: case GEGL_TILE_SET:
{ if (backend_tm->priv->write == FALSE)
GeglTile *tile = data; {
if (backend_tm->priv->write == FALSE) g_warning ("writing to a read only geglbuffer");
return NULL; return NULL;
gimp_tile_write (backend_tm, x, y, z, gegl_tile_get_data (tile)); }
gegl_tile_mark_as_stored (tile); if (backend_tm->priv->mul > 1)
return NULL; gimp_tile_write_mul (backend_tm, x, y, gegl_tile_get_data (data));
} else
gimp_tile_write (backend_tm, x, y, gegl_tile_get_data (data));
gegl_tile_mark_as_stored (data);
return NULL;
case GEGL_TILE_IDLE: case GEGL_TILE_IDLE:
case GEGL_TILE_VOID: case GEGL_TILE_VOID:
@ -206,11 +222,60 @@ gimp_tile_backend_tile_manager_command (GeglTileSource *tile_store,
return NULL; return NULL;
} }
static GeglTile *
gimp_tile_read (GimpTileBackendTileManager *backend_tm,
gint x,
gint y)
{
GeglTileBackend *backend;
GeglTile *tile;
gint tile_size;
Tile *gimp_tile;
gint tile_stride;
gint gimp_tile_stride;
int row;
backend = GEGL_TILE_BACKEND (backend_tm);
gimp_tile = tile_manager_get_at (backend_tm->priv->tile_manager,
x, y, TRUE, backend_tm->priv->write);
if (!gimp_tile)
return NULL;
g_return_val_if_fail (gimp_tile != NULL, NULL);
tile_size = gegl_tile_backend_get_tile_size (backend);
tile_stride = TILE_WIDTH * tile_bpp (gimp_tile);
gimp_tile_stride = tile_ewidth (gimp_tile) * tile_bpp (gimp_tile);
if (tile_stride == gimp_tile_stride &&
TILE_HEIGHT == tile_eheight (gimp_tile))
{
/* use the GimpTile directly as GEGL tile */
tile = gegl_tile_new_bare ();
gegl_tile_set_data_full (tile, tile_data_pointer (gimp_tile, 0, 0),
tile_size,
backend_tm->priv->write?
tile_done_writing:tile_done,
gimp_tile);
}
else
{
/* create a copy of the tile */
tile = gegl_tile_new (tile_size);
for (row = 0; row < tile_eheight (gimp_tile); row++)
{
memcpy (gegl_tile_get_data (tile) + row * tile_stride,
tile_data_pointer (gimp_tile, 0, row),
gimp_tile_stride);
}
tile_release (gimp_tile, backend_tm->priv->write);
}
return tile;
}
static void static void
gimp_tile_write (GimpTileBackendTileManager *backend_tm, gimp_tile_write (GimpTileBackendTileManager *backend_tm,
gint x, gint x,
gint y, gint y,
gint z,
guchar *source) guchar *source)
{ {
Tile *gimp_tile; Tile *gimp_tile;
@ -245,6 +310,104 @@ gimp_tile_write (GimpTileBackendTileManager *backend_tm,
tile_release (gimp_tile, TRUE); tile_release (gimp_tile, TRUE);
} }
static GeglTile *
gimp_tile_read_mul (GimpTileBackendTileManager *backend_tm,
gint x,
gint y)
{
GeglTileBackend *backend;
GeglTile *tile;
gint tile_size;
int u, v;
int mul = backend_tm->priv->mul;
unsigned char *tile_data;
void *validate_proc;
x *= mul;
y *= mul;
validate_proc = backend_tm->priv->tile_manager->validate_proc;
backend_tm->priv->tile_manager->validate_proc = NULL;
backend = GEGL_TILE_BACKEND (backend_tm);
tile_size = gegl_tile_backend_get_tile_size (backend);
tile = gegl_tile_new (tile_size);
tile_data = gegl_tile_get_data (tile);
for (u = 0; u < mul; u++)
for (v = 0; v < mul; v++)
{
Tile *gimp_tile;
gimp_tile = tile_manager_get_at (backend_tm->priv->tile_manager,
x+u, y+v, TRUE, FALSE);
if (gimp_tile)
{
gint ewidth = tile_ewidth (gimp_tile);
gint eheight = tile_eheight (gimp_tile);
gint bpp = tile_bpp (gimp_tile);
gint tile_stride = mul * TILE_WIDTH * bpp;
gint gimp_tile_stride = ewidth * bpp;
gint row;
for (row = 0; row < eheight; row++)
{
memcpy (tile_data + (row + TILE_HEIGHT * v) * tile_stride + u * TILE_WIDTH * bpp,
tile_data_pointer (gimp_tile, 0, row),
gimp_tile_stride);
}
tile_release (gimp_tile, FALSE);
}
}
backend_tm->priv->tile_manager->validate_proc = validate_proc;
return tile;
}
static void
gimp_tile_write_mul (GimpTileBackendTileManager *backend_tm,
gint x,
gint y,
guchar *source)
{
int u, v;
int mul = backend_tm->priv->mul;
void *validate_proc;
g_assert (backend_tm->priv->write);
x *= mul;
y *= mul;
validate_proc = backend_tm->priv->tile_manager->validate_proc;
backend_tm->priv->tile_manager->validate_proc = NULL;
for (v = 0; v < mul; v++)
for (u = 0; u < mul; u++)
{
Tile *gimp_tile = tile_manager_get_at (backend_tm->priv->tile_manager,
x+u, y+v, TRUE, TRUE);
if (gimp_tile)
{
gint ewidth = tile_ewidth (gimp_tile);
gint eheight = tile_eheight (gimp_tile);
gint bpp = tile_bpp (gimp_tile);
gint tile_stride = mul * TILE_WIDTH * bpp;
gint gimp_tile_stride = ewidth * bpp;
gint row;
for (row = 0; row < eheight; row++)
memcpy (tile_data_pointer (gimp_tile, 0, row),
source + (row + v * TILE_HEIGHT) * tile_stride + u * TILE_WIDTH * bpp,
gimp_tile_stride);
tile_release (gimp_tile, TRUE);
}
}
backend_tm->priv->tile_manager->validate_proc = validate_proc;
}
GeglTileBackend * GeglTileBackend *
gimp_tile_backend_tile_manager_new (TileManager *tm, gimp_tile_backend_tile_manager_new (TileManager *tm,
const Babl *format, const Babl *format,
@ -256,23 +419,31 @@ gimp_tile_backend_tile_manager_new (TileManager *tm,
gint width = tile_manager_width (tm); gint width = tile_manager_width (tm);
gint height = tile_manager_height (tm); gint height = tile_manager_height (tm);
gint bpp = tile_manager_bpp (tm); gint bpp = tile_manager_bpp (tm);
gint mul = gimp_gegl_tile_mul ();
GeglRectangle rect = { 0, 0, width, height }; GeglRectangle rect = { 0, 0, width, height };
write = TRUE;
g_return_val_if_fail (format == NULL || g_return_val_if_fail (format == NULL ||
babl_format_get_bytes_per_pixel (format) == babl_format_get_bytes_per_pixel (format) ==
babl_format_get_bytes_per_pixel (gimp_bpp_to_babl_format (bpp, TRUE)), babl_format_get_bytes_per_pixel (gimp_bpp_to_babl_format (bpp, TRUE)),
NULL); NULL);
if (tm->validate_proc)
mul = 1;
if (! format) if (! format)
format = gimp_bpp_to_babl_format (bpp, TRUE); format = gimp_bpp_to_babl_format (bpp, TRUE);
ret = g_object_new (GIMP_TYPE_TILE_BACKEND_TILE_MANAGER, ret = g_object_new (GIMP_TYPE_TILE_BACKEND_TILE_MANAGER,
"tile-width", TILE_WIDTH, "tile-width", TILE_WIDTH * mul,
"tile-height", TILE_HEIGHT, "tile-height", TILE_HEIGHT * mul,
"format", format, "format", format,
NULL); NULL);
backend_tm = GIMP_TILE_BACKEND_TILE_MANAGER (ret); backend_tm = GIMP_TILE_BACKEND_TILE_MANAGER (ret);
backend_tm->priv->write = write; backend_tm->priv->write = write;
backend_tm->priv->mul = mul;
backend_tm->priv->tile_manager = tile_manager_ref (tm); backend_tm->priv->tile_manager = tile_manager_ref (tm);