From ec3dc3870fab887b78b2cc3414f3131ae2f23d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Tue, 20 Mar 2012 17:36:14 +0000 Subject: [PATCH] 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.) --- app/gegl/gimptilebackendtilemanager.c | 291 ++++++++++++++++++++------ 1 file changed, 231 insertions(+), 60 deletions(-) diff --git a/app/gegl/gimptilebackendtilemanager.c b/app/gegl/gimptilebackendtilemanager.c index 043bf270e5..daeefb76dc 100644 --- a/app/gegl/gimptilebackendtilemanager.c +++ b/app/gegl/gimptilebackendtilemanager.c @@ -2,7 +2,8 @@ * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimptilebackendtilemanager.c - * Copyright (C) 2011 Øyvind Kolås + * Copyright (C) 2011,2012 Øyvind Kolås + * 2011 Martin Nordholts * * 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 @@ -20,6 +21,7 @@ #include "config.h" +#include #include #include @@ -32,6 +34,7 @@ #include "base/tile.h" #include "base/tile-manager.h" +#include "base/tile-manager-private.h" #include "gimptilebackendtilemanager.h" #include "gimp-gegl-utils.h" @@ -41,8 +44,49 @@ struct _GimpTileBackendTileManagerPrivate { TileManager *tile_manager; 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); @@ -54,12 +98,24 @@ static gpointer gimp_tile_backend_tile_manager_command (GeglTileSource *tile_s gint z, gpointer data); -static void gimp_tile_write (GimpTileBackendTileManager *ram, +static void gimp_tile_write (GimpTileBackendTileManager *backend_tm, gint x, gint y, - gint z, 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, GEGL_TYPE_TILE_BACKEND) @@ -131,68 +187,28 @@ gimp_tile_backend_tile_manager_command (GeglTileSource *tile_store, gpointer data) { GimpTileBackendTileManager *backend_tm; - GeglTileBackend *backend; backend_tm = GIMP_TILE_BACKEND_TILE_MANAGER (tile_store); - backend = GEGL_TILE_BACKEND (tile_store); switch (command) { case GEGL_TILE_GET: - { - GeglTile *tile; - gint tile_size; - 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; - } - + if (backend_tm->priv->mul > 1) + return gimp_tile_read_mul (backend_tm, x, y); + return gimp_tile_read (backend_tm, x, y); case GEGL_TILE_SET: - { - GeglTile *tile = data; - if (backend_tm->priv->write == FALSE) + if (backend_tm->priv->write == FALSE) + { + g_warning ("writing to a read only geglbuffer"); return NULL; - gimp_tile_write (backend_tm, x, y, z, gegl_tile_get_data (tile)); - gegl_tile_mark_as_stored (tile); - return NULL; - } + } + if (backend_tm->priv->mul > 1) + 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_VOID: @@ -206,11 +222,60 @@ gimp_tile_backend_tile_manager_command (GeglTileSource *tile_store, 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 gimp_tile_write (GimpTileBackendTileManager *backend_tm, gint x, gint y, - gint z, guchar *source) { Tile *gimp_tile; @@ -245,6 +310,104 @@ gimp_tile_write (GimpTileBackendTileManager *backend_tm, 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 * gimp_tile_backend_tile_manager_new (TileManager *tm, const Babl *format, @@ -256,23 +419,31 @@ gimp_tile_backend_tile_manager_new (TileManager *tm, gint width = tile_manager_width (tm); gint height = tile_manager_height (tm); gint bpp = tile_manager_bpp (tm); + gint mul = gimp_gegl_tile_mul (); GeglRectangle rect = { 0, 0, width, height }; + write = TRUE; + g_return_val_if_fail (format == NULL || babl_format_get_bytes_per_pixel (format) == babl_format_get_bytes_per_pixel (gimp_bpp_to_babl_format (bpp, TRUE)), NULL); + if (tm->validate_proc) + mul = 1; + if (! format) format = gimp_bpp_to_babl_format (bpp, TRUE); ret = g_object_new (GIMP_TYPE_TILE_BACKEND_TILE_MANAGER, - "tile-width", TILE_WIDTH, - "tile-height", TILE_HEIGHT, + "tile-width", TILE_WIDTH * mul, + "tile-height", TILE_HEIGHT * mul, "format", format, NULL); + backend_tm = GIMP_TILE_BACKEND_TILE_MANAGER (ret); backend_tm->priv->write = write; + backend_tm->priv->mul = mul; backend_tm->priv->tile_manager = tile_manager_ref (tm);