void gimp_tile_handler_projection_invalidate (GimpTileHandlerProjection *projection, gint x, gint y, gint width, gint height) { cairo_rectangle_int_t rect = { x, y, width, height }; gint tile_x1; gint tile_y1; gint tile_x2; gint tile_y2; gint tile_x; gint tile_y; g_return_if_fail (GIMP_IS_TILE_HANDLER_PROJECTION (projection)); cairo_region_union_rectangle (projection->dirty_region, &rect); tile_x1 = x / projection->tile_width; tile_y1 = y / projection->tile_height; tile_x2 = (x + width - 1) / projection->tile_width; tile_y2 = (y + height - 1) / projection->tile_height; for (tile_y = tile_y1; tile_y <= tile_y2; tile_y++) { for (tile_x = tile_x1; tile_x <= tile_x2; tile_x++) { gimp_tile_handler_projection_void_pyramid (GEGL_TILE_SOURCE (projection), tile_x / 2, tile_y / 2, 1); } } }
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 void gimp_tile_handler_projection_init (GimpTileHandlerProjection *projection) { GeglTileSource *source = GEGL_TILE_SOURCE (projection); source->command = gimp_tile_handler_projection_command; projection->dirty_region = cairo_region_create (); }
int main(int argc, char **argv) { GeglTile *tile; GeglBuffer *buf_a, *buf_b, *buf_small_lin, *buf_big_lin; gpointer shared_data = NULL; gboolean result = TRUE; gpointer scratch_data; GeglRectangle buffer_rect = *GEGL_RECTANGLE(0, 0, 128, 128); gegl_init (&argc, &argv); buf_a = gegl_buffer_new (&buffer_rect, babl_format("RGBA u8")); buf_b = gegl_buffer_new (&buffer_rect, babl_format("RGBA u8")); buf_small_lin = gegl_buffer_linear_new (&buffer_rect, babl_format("RGBA float")); buf_big_lin = gegl_buffer_linear_new (GEGL_RECTANGLE(0, 0, 1024, 1024), babl_format("RGBA float")); tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (buf_a), 0, 0, 0); shared_data = gegl_tile_get_data(tile); gegl_tile_unref (tile); if (!assert_is_empty (buf_a, 0, 0, shared_data)) result = FALSE; if (!assert_is_empty (buf_b, 0, 1, shared_data)) result = FALSE; if (!assert_is_empty (buf_a, 0, 0, shared_data)) result = FALSE; if (!assert_is_empty (buf_b, 0, 1, shared_data)) result = FALSE; if (!assert_is_empty (buf_small_lin, 0, 0, shared_data)) result = FALSE; if (!assert_is_unshared (buf_big_lin, 0, 0, shared_data)) result = FALSE; scratch_data = gegl_malloc(4 * buffer_rect.width * buffer_rect.height); gegl_buffer_get (buf_a, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE); gegl_buffer_get (buf_b, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE); gegl_buffer_get (buf_small_lin, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE); gegl_buffer_get (buf_big_lin, &buffer_rect, 1.0, babl_format("RGBA u8"), scratch_data, 0, GEGL_ABYSS_NONE); gegl_free (scratch_data); g_object_unref(buf_a); g_object_unref(buf_b); g_object_unref(buf_small_lin); g_object_unref(buf_big_lin); gegl_exit(); if (result) return SUCCESS; return FAILURE; }
gboolean gegl_tile_store (GeglTile *tile) { if (gegl_tile_is_stored (tile)) return TRUE; if (tile->tile_storage == NULL) return FALSE; return gegl_tile_source_set_tile (GEGL_TILE_SOURCE (tile->tile_storage), tile->x, tile->y, tile->z, tile); }
static void gegl_tile_void_pyramid (GeglTile *tile) { if (tile->tile_storage && tile->tile_storage->seen_zoom && tile->z == 0) /* we only accepting voiding the base level */ { _gegl_tile_void_pyramid (GEGL_TILE_SOURCE (tile->tile_storage), tile->x/2, tile->y/2, tile->z+1); return; } }
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 gboolean assert_is_empty (GeglBuffer *buf, gint x, gint y, gpointer shared_data) { gboolean result = TRUE; GeglTile *tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (buf), x, y, 0); if (!tile->is_zero_tile) { g_warning ("Not a zero tile"); result = FALSE; } if (gegl_tile_get_data(tile) != shared_data) { g_warning ("Not using shared data"); result = FALSE; } gegl_tile_unref (tile); return result; }
GeglBuffer * gegl_buffer_load (const gchar *path) { GeglBuffer *ret; LoadInfo *info = g_slice_new0 (LoadInfo); info->path = g_strdup (path); info->i = g_open (info->path, O_RDONLY, 0770); GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "starting to load buffer %s", path); if (info->i == -1) { GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "failed top open %s for reading", path); return NULL; } { GeglBufferItem *header = gegl_buffer_read_header (info->i, &info->offset); g_assert (header); /*memcpy (&(info->header), header, sizeof (GeglBufferHeader));*/ info->header = *(&header->header); info->offset = info->header.next; /*g_free (header);*/ /* is there a pointer to a string or something we're missing? */ } info->tile_size = info->header.tile_width * info->header.tile_height * info->header.bytes_per_pixel; info->format = babl_format (info->header.description); ret = g_object_new (GEGL_TYPE_BUFFER, "format", info->format, "tile-width", info->header.tile_width, "tile-height", info->header.tile_height, "height", info->header.height, "width", info->header.width, "path", path, NULL); /* sanity check, should probably report error condition and return safely instead */ g_assert (babl_format_get_bytes_per_pixel (info->format) == info->header.bytes_per_pixel); info->tiles = gegl_buffer_read_index (info->i, &info->offset); /* load each tile */ { GList *iter; gint i = 0; for (iter = info->tiles; iter; iter = iter->next) { GeglBufferTile *entry = iter->data; guchar *data; GeglTile *tile; tile = gegl_tile_source_get_tile (GEGL_TILE_SOURCE (ret), entry->x, entry->y, entry->z); if (info->offset != entry->offset) { seekto (info, entry->offset); } /*g_assert (info->offset == entry->offset);*/ g_assert (tile); gegl_tile_lock (tile); data = gegl_tile_get_data (tile); g_assert (data); { ssize_t sz_read = read (info->i, data, info->tile_size); if(sz_read != -1) info->offset += sz_read; } /*g_assert (info->offset == entry->offset + info->tile_size);*/ gegl_tile_unlock (tile); gegl_tile_unref (tile); i++; } GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "%i tiles loaded",i); } GEGL_NOTE (GEGL_DEBUG_BUFFER_LOAD, "buffer loaded %s", info->path); load_info_destroy (info); return ret; }
static void gegl_tile_backend_file_load_index (GeglTileBackendFile *self, gboolean block) { GeglBufferHeader new_header; GList *iter; GeglTileBackend *backend; goffset offset = 0; goffset max=0; gint tile_size; /* compute total from and next pre alloc by monitoring tiles as they * are added here */ /* reload header */ new_header = gegl_buffer_read_header (self->i, &offset)->header; self->foffset = 256; while (new_header.flags & GEGL_FLAG_LOCKED) { g_usleep (50000); new_header = gegl_buffer_read_header (self->i, &offset)->header; self->foffset = 256; } if (new_header.rev == self->header.rev) { GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "header not changed: %s", self->path); return; } else { self->header=new_header; GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "loading index: %s", self->path); } tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)); offset = self->header.next; self->tiles = gegl_buffer_read_index (self->i, &offset); self->foffset = -1; backend = GEGL_TILE_BACKEND (self); for (iter = self->tiles; iter; iter=iter->next) { GeglBufferItem *item = iter->data; GeglBufferItem *existing = g_hash_table_lookup (self->index, item); if (item->tile.offset > max) max = item->tile.offset + tile_size; if (existing) { if (existing->tile.rev == item->tile.rev) { g_assert (existing->tile.offset == item->tile.offset); existing->tile = item->tile; g_free (item); continue; } else { GeglTileStorage *storage = (void*)gegl_tile_backend_peek_storage (backend); GeglRectangle rect; g_hash_table_remove (self->index, existing); gegl_tile_source_refetch (GEGL_TILE_SOURCE (storage), existing->tile.x, existing->tile.y, existing->tile.z); if (existing->tile.z == 0) { rect.width = self->header.tile_width; rect.height = self->header.tile_height; rect.x = existing->tile.x * self->header.tile_width; rect.y = existing->tile.y * self->header.tile_height; } g_free (existing); g_signal_emit_by_name (storage, "changed", &rect, NULL); } } g_hash_table_insert (self->index, iter->data, iter->data); } g_list_free (self->tiles); g_slist_free (self->free_list); self->free_list = NULL; self->next_pre_alloc = max; /* if bigger than own? */ self->total = max; self->tiles = NULL; }
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; }