summaryrefslogtreecommitdiffstats
path: root/libgimp/gimptilebackendplugin.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:23:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:23:22 +0000
commite42129241681dde7adae7d20697e7b421682fbb4 (patch)
treeaf1fe815a5e639e68e59fabd8395ec69458b3e5e /libgimp/gimptilebackendplugin.c
parentInitial commit. (diff)
downloadgimp-upstream/2.10.22.tar.xz
gimp-upstream/2.10.22.zip
Adding upstream version 2.10.22.upstream/2.10.22upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libgimp/gimptilebackendplugin.c')
-rw-r--r--libgimp/gimptilebackendplugin.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/libgimp/gimptilebackendplugin.c b/libgimp/gimptilebackendplugin.c
new file mode 100644
index 0000000..d1767fa
--- /dev/null
+++ b/libgimp/gimptilebackendplugin.c
@@ -0,0 +1,313 @@
+/* gimptilebackendtilemanager.c
+ * Copyright (C) 2012 Øyvind Kolås <pippin@gimp.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <gegl.h>
+
+#define GIMP_DISABLE_DEPRECATION_WARNINGS
+
+#include "gimp.h"
+#include "gimptilebackendplugin.h"
+
+
+#define TILE_WIDTH gimp_tile_width()
+#define TILE_HEIGHT gimp_tile_height()
+
+
+struct _GimpTileBackendPluginPrivate
+{
+ GimpDrawable *drawable;
+ gboolean shadow;
+ gint mul;
+};
+
+
+static gint
+gimp_gegl_tile_mul (void)
+{
+ static gint mul = 1;
+ static gboolean inited = FALSE;
+
+ if (G_LIKELY (inited))
+ return mul;
+
+ inited = TRUE;
+
+ 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_plugin_finalize (GObject *object);
+static gpointer gimp_tile_backend_plugin_command (GeglTileSource *tile_store,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data);
+
+static void gimp_tile_write_mul (GimpTileBackendPlugin *backend_plugin,
+ gint x,
+ gint y,
+ guchar *source);
+
+static GeglTile * gimp_tile_read_mul (GimpTileBackendPlugin *backend_plugin,
+ gint x,
+ gint y);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpTileBackendPlugin, _gimp_tile_backend_plugin,
+ GEGL_TYPE_TILE_BACKEND)
+
+#define parent_class _gimp_tile_backend_plugin_parent_class
+
+
+static GMutex backend_plugin_mutex;
+
+
+static void
+_gimp_tile_backend_plugin_class_init (GimpTileBackendPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gimp_tile_backend_plugin_finalize;
+}
+
+static void
+_gimp_tile_backend_plugin_init (GimpTileBackendPlugin *backend)
+{
+ GeglTileSource *source = GEGL_TILE_SOURCE (backend);
+
+ backend->priv = _gimp_tile_backend_plugin_get_instance_private (backend);
+
+ source->command = gimp_tile_backend_plugin_command;
+}
+
+static void
+gimp_tile_backend_plugin_finalize (GObject *object)
+{
+ GimpTileBackendPlugin *backend = GIMP_TILE_BACKEND_PLUGIN (object);
+
+ if (backend->priv->drawable) /* This also causes a flush */
+ gimp_drawable_detach (backend->priv->drawable);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gpointer
+gimp_tile_backend_plugin_command (GeglTileSource *tile_store,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data)
+{
+ GimpTileBackendPlugin *backend_plugin = GIMP_TILE_BACKEND_PLUGIN (tile_store);
+ gpointer result = NULL;
+
+ switch (command)
+ {
+ case GEGL_TILE_GET:
+ /* TODO: fetch mipmapped tiles directly from gimp, instead of returning
+ * NULL to render them locally
+ */
+ if (z == 0)
+ {
+ g_mutex_lock (&backend_plugin_mutex);
+
+ result = gimp_tile_read_mul (backend_plugin, x, y);
+
+ g_mutex_unlock (&backend_plugin_mutex);
+ }
+ break;
+
+ case GEGL_TILE_SET:
+ /* TODO: actually store mipmapped tiles */
+ if (z == 0)
+ {
+ g_mutex_lock (&backend_plugin_mutex);
+
+ gimp_tile_write_mul (backend_plugin, x, y, gegl_tile_get_data (data));
+
+ g_mutex_unlock (&backend_plugin_mutex);
+ }
+
+ gegl_tile_mark_as_stored (data);
+ break;
+
+ case GEGL_TILE_FLUSH:
+ g_mutex_lock (&backend_plugin_mutex);
+
+ gimp_drawable_flush (backend_plugin->priv->drawable);
+
+ g_mutex_unlock (&backend_plugin_mutex);
+ break;
+
+ default:
+ result = gegl_tile_backend_command (GEGL_TILE_BACKEND (tile_store),
+ command, x, y, z, data);
+ break;
+ }
+
+ return result;
+}
+
+static GeglTile *
+gimp_tile_read_mul (GimpTileBackendPlugin *backend_plugin,
+ gint x,
+ gint y)
+{
+ GimpTileBackendPluginPrivate *priv = backend_plugin->priv;
+ GeglTileBackend *backend = GEGL_TILE_BACKEND (backend_plugin);
+ GeglTile *tile;
+ gint tile_size;
+ gint u, v;
+ gint mul = priv->mul;
+ guchar *tile_data;
+
+ x *= mul;
+ y *= mul;
+
+ 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++)
+ {
+ GimpTile *gimp_tile;
+
+ if (x + u >= priv->drawable->ntile_cols ||
+ y + v >= priv->drawable->ntile_rows)
+ continue;
+
+ gimp_tile = gimp_drawable_get_tile (priv->drawable,
+ priv->shadow,
+ y + v, x + u);
+ _gimp_tile_ref_nocache (gimp_tile, TRUE);
+
+ {
+ gint ewidth = gimp_tile->ewidth;
+ gint eheight = gimp_tile->eheight;
+ gint bpp = gimp_tile->bpp;
+ 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,
+ ((gchar *) gimp_tile->data) + row * gimp_tile_stride,
+ gimp_tile_stride);
+ }
+ }
+
+ gimp_tile_unref (gimp_tile, FALSE);
+ }
+ }
+
+ return tile;
+}
+
+static void
+gimp_tile_write_mul (GimpTileBackendPlugin *backend_plugin,
+ gint x,
+ gint y,
+ guchar *source)
+{
+ GimpTileBackendPluginPrivate *priv = backend_plugin->priv;
+ gint u, v;
+ gint mul = priv->mul;
+
+ x *= mul;
+ y *= mul;
+
+ for (v = 0; v < mul; v++)
+ {
+ for (u = 0; u < mul; u++)
+ {
+ GimpTile *gimp_tile;
+
+ if (x + u >= priv->drawable->ntile_cols ||
+ y + v >= priv->drawable->ntile_rows)
+ continue;
+
+ gimp_tile = gimp_drawable_get_tile (priv->drawable,
+ priv->shadow,
+ y+v, x+u);
+ _gimp_tile_ref_nocache (gimp_tile, FALSE);
+
+ {
+ gint ewidth = gimp_tile->ewidth;
+ gint eheight = gimp_tile->eheight;
+ gint bpp = gimp_tile->bpp;
+ gint tile_stride = mul * TILE_WIDTH * bpp;
+ gint gimp_tile_stride = ewidth * bpp;
+ gint row;
+
+ for (row = 0; row < eheight; row++)
+ memcpy (((gchar *)gimp_tile->data) + row * gimp_tile_stride,
+ source + (row + v * TILE_HEIGHT) *
+ tile_stride + u * TILE_WIDTH * bpp,
+ gimp_tile_stride);
+ }
+
+ gimp_tile_unref (gimp_tile, TRUE);
+ }
+ }
+}
+
+GeglTileBackend *
+_gimp_tile_backend_plugin_new (GimpDrawable *drawable,
+ gint shadow)
+{
+ GeglTileBackend *backend;
+ GimpTileBackendPlugin *backend_plugin;
+ const Babl *format;
+ gint width = gimp_drawable_width (drawable->drawable_id);
+ gint height = gimp_drawable_height (drawable->drawable_id);
+ gint mul = gimp_gegl_tile_mul ();
+
+ format = gimp_drawable_get_format (drawable->drawable_id);
+
+ backend = g_object_new (GIMP_TYPE_TILE_BACKEND_PLUGIN,
+ "tile-width", TILE_WIDTH * mul,
+ "tile-height", TILE_HEIGHT * mul,
+ "format", format,
+ NULL);
+
+ backend_plugin = GIMP_TILE_BACKEND_PLUGIN (backend);
+
+ backend_plugin->priv->drawable = drawable;
+ backend_plugin->priv->mul = mul;
+ backend_plugin->priv->shadow = shadow;
+
+ gegl_tile_backend_set_extent (backend,
+ GEGL_RECTANGLE (0, 0, width, height));
+
+ return backend;
+}