static void gegl_buffer_dispose (GObject *object) { GeglBuffer *buffer = GEGL_BUFFER (object); GeglTileHandler *handler = GEGL_TILE_HANDLER (object); gegl_buffer_sample_cleanup (buffer); if (gegl_cl_is_accelerated ()) gegl_buffer_cl_cache_invalidate (GEGL_BUFFER (object), NULL); if (handler->source && GEGL_IS_TILE_STORAGE (handler->source)) { GeglTileBackend *backend = gegl_buffer_backend (buffer); /* only flush non-internal backends,. */ if (!(GEGL_IS_TILE_BACKEND_FILE (backend) || GEGL_IS_TILE_BACKEND_RAM (backend) || GEGL_IS_TILE_BACKEND_TILE_DIR (backend))) gegl_buffer_flush (buffer); gegl_tile_source_reinit (GEGL_TILE_SOURCE (handler->source)); #if 0 g_object_unref (handler->source); handler->source = NULL; /* this might be a dangerous way of marking that we have already voided */ #endif } _gegl_buffer_drop_hot_tile (buffer); G_OBJECT_CLASS (parent_class)->dispose (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 (G_UNLIKELY(!empty->tile)) { gint tile_size = gegl_tile_backend_get_tile_size (empty->backend); empty->tile = gegl_tile_new (tile_size); memset (gegl_tile_get_data (empty->tile), 0x00, tile_size); empty->tile->is_zero_tile = 1; } return gegl_tile_handler_dup_tile (GEGL_TILE_HANDLER (empty), empty->tile, x, y, z); }
GeglTileHandler * gimp_tile_handler_projection_new (GeglNode *graph) { GimpTileHandlerProjection *projection; g_return_val_if_fail (GEGL_IS_NODE (graph), NULL); projection = g_object_new (GIMP_TYPE_TILE_HANDLER_PROJECTION, NULL); projection->graph = g_object_ref (graph); return GEGL_TILE_HANDLER (projection); }
static gpointer gegl_buffer_command (GeglTileSource *source, GeglTileCommand command, gint x, gint y, gint z, gpointer data) { GeglTileHandler *handler = GEGL_TILE_HANDLER (source); switch (command) { case GEGL_TILE_GET: return gegl_buffer_get_tile (source, x, y, z); default: return gegl_tile_handler_source_command (handler, command, x, y, z, data); } }
GeglTileBackend * gegl_buffer_backend2 (GeglBuffer *buffer) { GeglTileSource *tmp = GEGL_TILE_SOURCE (buffer); if (!tmp) return NULL; do { tmp = GEGL_TILE_HANDLER (tmp)->source; } while (tmp && !GEGL_IS_TILE_BACKEND (tmp)); if (!tmp && !GEGL_IS_TILE_BACKEND (tmp)) return NULL; return (GeglTileBackend *) tmp; }
static GeglTile * get_tile (GeglTileSource *gegl_tile_source, gint x, gint y, gint z) { GeglTileSource *source = ((GeglTileHandler *) gegl_tile_source)->source; GeglTileHandlerZoom *zoom = (GeglTileHandlerZoom *) gegl_tile_source; GeglTile *tile = NULL; const Babl *format = gegl_tile_backend_get_format (zoom->backend); GeglTileStorage *tile_storage; gint tile_width; gint tile_height; gint tile_size; if (source) tile = gegl_tile_source_get_tile (source, x, y, z); if (tile) return tile; if (z == 0)/* at base level with no tile found->send null, and shared empty tile will be used instead */ { return NULL; } tile_storage = _gegl_tile_handler_get_tile_storage ((GeglTileHandler *) zoom); if (z > tile_storage->seen_zoom) tile_storage->seen_zoom = z; g_object_get (zoom->backend, "tile-width", &tile_width, "tile-height", &tile_height, "tile-size", &tile_size, NULL); { gint i, j; GeglTile *source_tile[2][2] = { { NULL, NULL }, { NULL, NULL } }; for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) { /* we get the tile from ourselves, to make successive rescales work * correctly */ source_tile[i][j] = gegl_tile_source_get_tile (gegl_tile_source, x * 2 + i, y * 2 + j, z - 1); } if (source_tile[0][0] == NULL && source_tile[0][1] == NULL && source_tile[1][0] == NULL && source_tile[1][1] == NULL) { return NULL; /* no data from level below, return NULL and let GeglTileHandlerEmpty fill in the shared empty tile */ } g_assert (tile == NULL); tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (zoom), x, y, z); gegl_tile_lock (tile); for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) { if (source_tile[i][j]) { set_half (tile, source_tile[i][j], tile_width, tile_height, format, i, j); gegl_tile_unref (source_tile[i][j]); } else { set_blank (tile, tile_width, tile_height, format, i, j); } } gegl_tile_unlock (tile); } return tile; }
static GeglTile * gimp_tile_handler_projection_validate (GeglTileSource *source, GeglTile *tile, gint x, gint y) { GimpTileHandlerProjection *projection; cairo_region_t *tile_region; cairo_rectangle_int_t tile_rect; projection = GIMP_TILE_HANDLER_PROJECTION (source); if (cairo_region_is_empty (projection->dirty_region)) return tile; tile_region = cairo_region_copy (projection->dirty_region); tile_rect.x = x * projection->tile_width; tile_rect.y = y * projection->tile_height; tile_rect.width = projection->tile_width; tile_rect.height = projection->tile_height; cairo_region_intersect_rectangle (tile_region, &tile_rect); if (! cairo_region_is_empty (tile_region)) { gint tile_bpp; gint tile_stride; gint n_rects; gint i; if (! tile) tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (source), x, y, 0); cairo_region_subtract_rectangle (projection->dirty_region, &tile_rect); tile_bpp = babl_format_get_bytes_per_pixel (projection->format); tile_stride = tile_bpp * projection->tile_width; gegl_tile_lock (tile); n_rects = cairo_region_num_rectangles (tile_region); #if 0 g_printerr ("%d ", n_rects); #endif for (i = 0; i < n_rects; i++) { cairo_rectangle_int_t blit_rect; cairo_region_get_rectangle (tile_region, i, &blit_rect); #if 0 g_printerr ("constructing projection at %d %d %d %d\n", blit_rect.x, blit_rect.y, blit_rect.width, blit_rect.height); #endif gegl_node_blit (projection->graph, 1.0, GEGL_RECTANGLE (blit_rect.x, blit_rect.y, blit_rect.width, blit_rect.height), projection->format, gegl_tile_get_data (tile) + (blit_rect.y % projection->tile_height) * tile_stride + (blit_rect.x % projection->tile_width) * tile_bpp, tile_stride, GEGL_ABYSS_NONE); } gegl_tile_unlock (tile); } cairo_region_destroy (tile_region); return tile; }
static GObject * gegl_buffer_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; GeglBuffer *buffer; GeglTileBackend *backend; GeglTileHandler *handler; GeglTileSource *source; object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); buffer = GEGL_BUFFER (object); handler = GEGL_TILE_HANDLER (object); source = handler->source; backend = gegl_buffer_backend (buffer); if (source) { if (GEGL_IS_TILE_STORAGE (source)) buffer->format = GEGL_TILE_STORAGE (source)->format; else if (GEGL_IS_BUFFER (source)) buffer->format = GEGL_BUFFER (source)->format; } else { if (buffer->backend) { backend = buffer->backend; buffer->format = gegl_tile_backend_get_format (backend); } else { gboolean use_ram = FALSE; const char *maybe_path = NULL; if (!buffer->format) { g_warning ("Buffer constructed without format, assuming RGBA float"); buffer->format = babl_format("RGBA float"); } /* make a new backend & storage */ if (buffer->path) maybe_path = buffer->path; else maybe_path = gegl_config ()->swap; if (maybe_path) use_ram = g_ascii_strcasecmp (maybe_path, "ram") == 0; else use_ram = TRUE; if (use_ram == TRUE) { backend = g_object_new (GEGL_TYPE_TILE_BACKEND_RAM, "tile-width", buffer->tile_width, "tile-height", buffer->tile_height, "format", buffer->format, NULL); } else { if (buffer->path) { backend = g_object_new (GEGL_TYPE_TILE_BACKEND_FILE, "tile-width", buffer->tile_width, "tile-height", buffer->tile_height, "format", buffer->format, "path", buffer->path, NULL); } else { gchar *path = get_next_swap_path(); backend = g_object_new (GEGL_TYPE_TILE_BACKEND_FILE, "tile-width", buffer->tile_width, "tile-height", buffer->tile_height, "format", buffer->format, "path", path, NULL); g_free (path); } } buffer->backend = backend; } source = GEGL_TILE_SOURCE (gegl_tile_storage_new (backend)); gegl_tile_handler_set_source ((GeglTileHandler*)(buffer), source); g_object_unref (source); g_object_unref (backend); } /* Connect to the changed signal of source, this is used by some backends * (e.g. File) to notify of outside changes to the buffer. */ if (GEGL_IS_TILE_STORAGE (source)) { g_signal_connect (source, "changed", G_CALLBACK (gegl_buffer_storage_changed), buffer); } g_assert (backend); if (buffer->extent.width == -1 || buffer->extent.height == -1) /* no specified extents, inheriting from source */ { if (GEGL_IS_BUFFER (source)) { buffer->extent.x = GEGL_BUFFER (source)->extent.x; buffer->extent.y = GEGL_BUFFER (source)->extent.y; buffer->extent.width = GEGL_BUFFER (source)->extent.width; buffer->extent.height = GEGL_BUFFER (source)->extent.height; } else if (GEGL_IS_TILE_STORAGE (source)) { buffer->extent.x = 0; buffer->extent.y = 0; buffer->extent.width = GEGL_TILE_STORAGE (source)->width; buffer->extent.height = GEGL_TILE_STORAGE (source)->height; } else { buffer->extent.x = 0; buffer->extent.y = 0; buffer->extent.width = 0; buffer->extent.height = 0; } } buffer->abyss_tracks_extent = FALSE; if (buffer->abyss.width == 0 && buffer->abyss.height == 0 && buffer->abyss.x == 0 && buffer->abyss.y == 0) /* 0 sized extent == inherit buffer extent */ { buffer->abyss.x = buffer->extent.x; buffer->abyss.y = buffer->extent.y; buffer->abyss.width = buffer->extent.width; buffer->abyss.height = buffer->extent.height; buffer->abyss_tracks_extent = TRUE; } else if (buffer->abyss.width == 0 && buffer->abyss.height == 0) { g_warning ("peculiar abyss dimensions: %i,%i %ix%i", buffer->abyss.x, buffer->abyss.y, buffer->abyss.width, buffer->abyss.height); } else if (buffer->abyss.width == -1 || buffer->abyss.height == -1) { buffer->abyss.x = GEGL_BUFFER (source)->abyss.x - buffer->shift_x; buffer->abyss.y = GEGL_BUFFER (source)->abyss.y - buffer->shift_y; buffer->abyss.width = GEGL_BUFFER (source)->abyss.width; buffer->abyss.height = GEGL_BUFFER (source)->abyss.height; } /* intersect our own abyss with parent's abyss if it exists */ if (GEGL_IS_BUFFER (source)) { GeglRectangle parent; GeglRectangle request; GeglRectangle self; parent.x = GEGL_BUFFER (source)->abyss.x - buffer->shift_x; parent.y = GEGL_BUFFER (source)->abyss.y - buffer->shift_y; parent.width = GEGL_BUFFER (source)->abyss.width; parent.height = GEGL_BUFFER (source)->abyss.height; request.x = buffer->abyss.x; request.y = buffer->abyss.y; request.width = buffer->abyss.width; request.height = buffer->abyss.height; gegl_rectangle_intersect (&self, &parent, &request); /* Don't have the abyss track the extent if the intersection is * not the entire extent. Otherwise, setting the extent identical * to itself could suddenly make the abyss bigger. */ if (buffer->abyss_tracks_extent && (buffer->extent.x != self.x || buffer->extent.y != self.y || buffer->extent.width != self.width || buffer->extent.height != self.height) ) { buffer->abyss_tracks_extent = FALSE; } buffer->abyss.x = self.x; buffer->abyss.y = self.y; buffer->abyss.width = self.width; buffer->abyss.height = self.height; } /* compute our own total shift <- this should probably happen * approximatly first */ if (GEGL_IS_BUFFER (source)) { GeglBuffer *source_buf; source_buf = GEGL_BUFFER (source); buffer->shift_x += source_buf->shift_x; buffer->shift_y += source_buf->shift_y; } else { } buffer->tile_storage = gegl_buffer_tile_storage (buffer); /* intialize the soft format to be equivalent to the actual * format */ buffer->soft_format = buffer->format; return object; }