gimptilebackendplugin.c 9.16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* 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 <http://www.gnu.org/licenses/>.
 */

18 19
#include "config.h"

20 21
#include <stdlib.h>
#include <string.h>
22

23
#include <gegl.h>
24

25 26
#define GIMP_DISABLE_DEPRECATION_WARNINGS

27 28 29
#include "gimp.h"
#include "gimptilebackendplugin.h"

30

31
#define TILE_WIDTH  gimp_tile_width()
32
#define TILE_HEIGHT gimp_tile_height()
33

34

35 36 37 38
struct _GimpTileBackendPluginPrivate
{
  GimpDrawable *drawable;
  gboolean      shadow;
39
  gint          mul;
40 41
};

42 43 44

static gint
gimp_gegl_tile_mul (void)
45
{
46 47 48
  static gint     mul    = 2;
  static gboolean inited = FALSE;

49 50
  if (G_LIKELY (inited))
    return mul;
51 52 53

  inited = TRUE;

54 55
  if (g_getenv ("GIMP_GEGL_TILE_MUL"))
    mul = atoi (g_getenv ("GIMP_GEGL_TILE_MUL"));
56

57 58 59
  if (mul < 1)
    mul = 1;

60
  return mul;
61 62 63 64 65 66 67 68 69 70 71
}

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,
72 73 74
                                       gint                   x,
                                       gint                   y,
                                       guchar                *source);
75 76

static GeglTile * gimp_tile_read_mul (GimpTileBackendPlugin *backend_plugin,
77 78
                                      gint                   x,
                                      gint                   y);
79

80 81

G_DEFINE_TYPE (GimpTileBackendPlugin, _gimp_tile_backend_plugin,
82 83
               GEGL_TYPE_TILE_BACKEND)

84
#define parent_class _gimp_tile_backend_plugin_parent_class
85 86


87 88 89
static GMutex backend_plugin_mutex;


90
static void
91
_gimp_tile_backend_plugin_class_init (GimpTileBackendPluginClass *klass)
92 93 94 95 96 97
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->finalize = gimp_tile_backend_plugin_finalize;

  g_type_class_add_private (klass, sizeof (GimpTileBackendPluginPrivate));
98 99

  gimp_tile_cache_ntiles (64);
100 101 102
}

static void
103
_gimp_tile_backend_plugin_init (GimpTileBackendPlugin *backend)
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
{
  GeglTileSource *source = GEGL_TILE_SOURCE (backend);

  backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend,
                                               GIMP_TYPE_TILE_BACKEND_PLUGIN,
                                               GimpTileBackendPluginPrivate);

  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 */
120
    gimp_drawable_detach (backend->priv->drawable);
121 122 123 124 125 126

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static gpointer
gimp_tile_backend_plugin_command (GeglTileSource  *tile_store,
127 128 129 130 131
                                  GeglTileCommand  command,
                                  gint             x,
                                  gint             y,
                                  gint             z,
                                  gpointer         data)
132
{
133
  GimpTileBackendPlugin *backend_plugin = GIMP_TILE_BACKEND_PLUGIN (tile_store);
134
  gpointer               result         = NULL;
135 136 137 138

  switch (command)
    {
    case GEGL_TILE_GET:
139
      g_mutex_lock (&backend_plugin_mutex);
140 141 142

      result = gimp_tile_read_mul (backend_plugin, x, y);

143
      g_mutex_unlock (&backend_plugin_mutex);
144
      break;
145

146
    case GEGL_TILE_SET:
147
      g_mutex_lock (&backend_plugin_mutex);
148

149 150
      gimp_tile_write_mul (backend_plugin, x, y, gegl_tile_get_data (data));
      gegl_tile_mark_as_stored (data);
151

152
      g_mutex_unlock (&backend_plugin_mutex);
153
      break;
154

155
    case GEGL_TILE_FLUSH:
156
      g_mutex_lock (&backend_plugin_mutex);
157

158
      gimp_drawable_flush (backend_plugin->priv->drawable);
159

160
      g_mutex_unlock (&backend_plugin_mutex);
161
      break;
162

163 164 165 166
    default:
      g_assert (command < GEGL_TILE_LAST_COMMAND && command >= 0);
    }

167
  return result;
168 169 170 171
}

static GeglTile *
gimp_tile_read_mul (GimpTileBackendPlugin *backend_plugin,
172 173
                    gint                   x,
                    gint                   y)
174
{
175 176 177 178 179 180 181
  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;
182 183 184 185 186 187 188 189 190

  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++)
191 192 193 194 195 196 197 198 199 200 201 202 203 204
    {
      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 (gimp_tile);

205 206 207 208 209 210 211 212 213 214 215 216
          {
            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,
217
                        ((gchar *) gimp_tile->data) + row * gimp_tile_stride,
218 219 220
                        gimp_tile_stride);
              }
          }
221 222 223 224

          gimp_tile_unref (gimp_tile, FALSE);
        }
    }
225 226 227 228 229 230 231 232 233 234 235

  return tile;
}

static void
gimp_tile_write_mul (GimpTileBackendPlugin *backend_plugin,
                     gint                   x,
                     gint                   y,
                     guchar                *source)
{
  GimpTileBackendPluginPrivate *priv = backend_plugin->priv;
236 237
  gint                          u, v;
  gint                          mul = priv->mul;
238 239 240 241 242 243

  x *= mul;
  y *= mul;

  for (v = 0; v < mul; v++)
    {
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
      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 (gimp_tile);

          {
            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);
        }
274 275 276 277
    }
}

GeglTileBackend *
278 279
_gimp_tile_backend_plugin_new (GimpDrawable *drawable,
                               gint          shadow)
280
{
281 282 283 284 285 286
  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 ();
287

288
  format = gimp_drawable_get_format (drawable->drawable_id);
289

290 291 292 293 294
  backend = g_object_new (GIMP_TYPE_TILE_BACKEND_PLUGIN,
                          "tile-width",  TILE_WIDTH  * mul,
                          "tile-height", TILE_HEIGHT * mul,
                          "format",      format,
                          NULL);
295

296
  backend_plugin = GIMP_TILE_BACKEND_PLUGIN (backend);
297

298 299 300
  backend_plugin->priv->drawable = drawable;
  backend_plugin->priv->mul      = mul;
  backend_plugin->priv->shadow   = shadow;
301

302 303
  gegl_tile_backend_set_extent (backend,
                                GEGL_RECTANGLE (0, 0, width, height));
304

305
  return backend;
306
}