[gegl] gegl: keep track of valid region for mipmap levels
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] gegl: keep track of valid region for mipmap levels
- Date: Wed, 9 Jul 2014 06:53:45 +0000 (UTC)
commit 3a2d6fcba89c7f91b1155358ad8db1414e6fdc1d
Author: Øyvind Kolås <pippin gimp org>
Date: Wed Jul 9 00:56:53 2014 +0200
gegl: keep track of valid region for mipmap levels
gegl/buffer/gegl-cache.c | 40 +++++++++++----
gegl/buffer/gegl-cache.h | 7 ++-
gegl/graph/gegl-node.c | 8 ++--
gegl/process/gegl-eval-manager.c | 2 +-
gegl/process/gegl-graph-traversal-debug.c | 2 +-
gegl/process/gegl-graph-traversal.c | 80 ++++++++++++++++------------
gegl/process/gegl-graph-traversal.h | 3 +-
gegl/process/gegl-processor.c | 24 ++++++---
8 files changed, 106 insertions(+), 60 deletions(-)
---
diff --git a/gegl/buffer/gegl-cache.c b/gegl/buffer/gegl-cache.c
index ed131d2..79ce88b 100644
--- a/gegl/buffer/gegl-cache.c
+++ b/gegl/buffer/gegl-cache.c
@@ -66,10 +66,12 @@ static void
gegl_cache_constructed (GObject *object)
{
GeglCache *self = GEGL_CACHE (object);
+ gint i;
G_OBJECT_CLASS (gegl_cache_parent_class)->constructed (object);
- self->valid_region = gegl_region_new ();
+ for (i = 0; i < GEGL_CACHE_VALID_MIPMAPS; i++)
+ self->valid_region[i] = gegl_region_new ();
}
/* expand invalidated regions to be align with coordinates divisible by 8 in both
@@ -185,10 +187,12 @@ static void
finalize (GObject *gobject)
{
GeglCache *self = GEGL_CACHE (gobject);
+ gint i;
g_mutex_clear (&self->mutex);
- if (self->valid_region)
- gegl_region_destroy (self->valid_region);
+ for (i = 0; i < GEGL_CACHE_VALID_MIPMAPS; i++)
+ if (self->valid_region[i])
+ gegl_region_destroy (self->valid_region[i]);
G_OBJECT_CLASS (gegl_cache_parent_class)->finalize (gobject);
}
@@ -257,6 +261,7 @@ void
gegl_cache_invalidate (GeglCache *self,
const GeglRectangle *roi)
{
+ gint i;
g_mutex_lock (&self->mutex);
if (roi)
@@ -265,7 +270,8 @@ gegl_cache_invalidate (GeglCache *self,
GeglRegion *temp_region;
temp_region = gegl_region_rectangle (&expanded);
- gegl_region_subtract (self->valid_region, temp_region);
+ for (i = 0; i < GEGL_CACHE_VALID_MIPMAPS; i++)
+ gegl_region_subtract (self->valid_region[i], temp_region);
gegl_region_destroy (temp_region);
g_signal_emit (self, gegl_cache_signals[INVALIDATED], 0,
roi, NULL);
@@ -273,9 +279,12 @@ gegl_cache_invalidate (GeglCache *self,
else
{
GeglRectangle rect = { 0, 0, 0, 0 }; /* should probably be the extent of the cache */
- if (self->valid_region)
- gegl_region_destroy (self->valid_region);
- self->valid_region = gegl_region_new ();
+ for (i = 0; i < GEGL_CACHE_VALID_MIPMAPS; i++)
+ {
+ if (self->valid_region[i])
+ gegl_region_destroy (self->valid_region[i]);
+ self->valid_region[i] = gegl_region_new ();
+ }
g_signal_emit (self, gegl_cache_signals[INVALIDATED], 0,
&rect, NULL);
}
@@ -284,13 +293,17 @@ gegl_cache_invalidate (GeglCache *self,
void
gegl_cache_computed (GeglCache *self,
- const GeglRectangle *rect)
+ const GeglRectangle *rect,
+ gint level)
{
g_return_if_fail (GEGL_IS_CACHE (self));
g_return_if_fail (rect != NULL);
g_mutex_lock (&self->mutex);
- gegl_region_union_with_rect (self->valid_region, rect);
+
+ if (level <= GEGL_CACHE_VALID_MIPMAPS)
+ gegl_region_union_with_rect (self->valid_region[level], rect);
+
g_signal_emit (self, gegl_cache_signals[COMPUTED], 0, rect, NULL);
g_mutex_unlock (&self->mutex);
}
@@ -306,10 +319,17 @@ gegl_buffer_list_valid_rectangles (GeglBuffer *buffer,
gint *n_rectangles)
{
GeglCache *cache;
+ gint level = 0; /* should be an argument */
g_return_val_if_fail (GEGL_IS_CACHE (buffer), FALSE);
cache = GEGL_CACHE (buffer);
- gegl_region_get_rectangles (cache->valid_region, rectangles, n_rectangles);
+ if (level < 0)
+ level = 0;
+ if (level >= GEGL_CACHE_VALID_MIPMAPS)
+ level = GEGL_CACHE_VALID_MIPMAPS-1;
+
+ gegl_region_get_rectangles (cache->valid_region[level],
+ rectangles, n_rectangles);
return TRUE;
}
diff --git a/gegl/buffer/gegl-cache.h b/gegl/buffer/gegl-cache.h
index 38f1a50..d56b059 100644
--- a/gegl/buffer/gegl-cache.h
+++ b/gegl/buffer/gegl-cache.h
@@ -33,11 +33,13 @@ G_BEGIN_DECLS
typedef struct _GeglCacheClass GeglCacheClass;
+#define GEGL_CACHE_VALID_MIPMAPS 8
+
struct _GeglCache
{
GeglBuffer parent_instance;
- GeglRegion *valid_region;
+ GeglRegion *valid_region[GEGL_CACHE_VALID_MIPMAPS];
GMutex mutex;
};
@@ -50,7 +52,8 @@ GType gegl_cache_get_type (void) G_GNUC_CONST;
void gegl_cache_invalidate (GeglCache *self,
const GeglRectangle *roi);
void gegl_cache_computed (GeglCache *self,
- const GeglRectangle *rect);
+ const GeglRectangle *rect,
+ gint level);
G_END_DECLS
diff --git a/gegl/graph/gegl-node.c b/gegl/graph/gegl-node.c
index 05381d7..8fc8edc 100644
--- a/gegl/graph/gegl-node.c
+++ b/gegl/graph/gegl-node.c
@@ -1037,15 +1037,15 @@ gegl_node_blit (GeglNode *self,
if (scale != 1.0)
{
const GeglRectangle unscaled_roi = _gegl_get_required_for_scale (format, roi, scale);
+ gint level = gegl_mipmap_rendering_enabled()?gegl_level_from_scale (scale):0;
- gegl_node_blit_buffer2 (self, buffer, &unscaled_roi,
- gegl_mipmap_rendering_enabled()?gegl_level_from_scale (scale):0);
- gegl_cache_computed (cache, &unscaled_roi);
+ gegl_node_blit_buffer2 (self, buffer, &unscaled_roi, level);
+ gegl_cache_computed (cache, &unscaled_roi, level);
}
else
{
gegl_node_blit_buffer (self, buffer, roi);
- gegl_cache_computed (cache, roi);
+ gegl_cache_computed (cache, roi, 0);
}
}
diff --git a/gegl/process/gegl-eval-manager.c b/gegl/process/gegl-eval-manager.c
index 48ceaf0..9cd4afc 100644
--- a/gegl/process/gegl-eval-manager.c
+++ b/gegl/process/gegl-eval-manager.c
@@ -127,7 +127,7 @@ gegl_eval_manager_apply (GeglEvalManager *self,
GEGL_INSTRUMENT_END ("gegl", "prepare-graph");
GEGL_INSTRUMENT_START();
- gegl_graph_prepare_request (self->traversal, roi);
+ gegl_graph_prepare_request (self->traversal, roi, level);
GEGL_INSTRUMENT_END ("gegl", "prepare-request");
GEGL_INSTRUMENT_START();
diff --git a/gegl/process/gegl-graph-traversal-debug.c b/gegl/process/gegl-graph-traversal-debug.c
index 0b08346..7331b68 100644
--- a/gegl/process/gegl-graph-traversal-debug.c
+++ b/gegl/process/gegl-graph-traversal-debug.c
@@ -76,7 +76,7 @@ gegl_graph_dump_request (GeglNode *node,
GList *list_iter = NULL;
gegl_graph_prepare (path);
- gegl_graph_prepare_request (path, roi);
+ gegl_graph_prepare_request (path, roi, 0);
for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next)
{
diff --git a/gegl/process/gegl-graph-traversal.c b/gegl/process/gegl-graph-traversal.c
index abe5bf7..eff8bc4 100644
--- a/gegl/process/gegl-graph-traversal.c
+++ b/gegl/process/gegl-graph-traversal.c
@@ -203,9 +203,11 @@ gegl_graph_prepare (GeglGraphTraversal *path)
* the area that needs to be rendered from each node in the
* graph to fulfill this request.
*/
+
void
gegl_graph_prepare_request (GeglGraphTraversal *path,
- const GeglRectangle *request_roi)
+ const GeglRectangle *request_roi,
+ gint level)
{
GList *list_iter = NULL;
static const GeglRectangle empty_rect = {0, 0, 0, 0};
@@ -261,49 +263,59 @@ gegl_graph_prepare_request (GeglGraphTraversal *path,
if (request->width == 0 || request->height == 0)
{
gegl_operation_context_set_result_rect (context, &empty_rect);
+ continue;
}
- else if (node->cache &&
- gegl_region_rect_in (node->cache->valid_region, request) == GEGL_OVERLAP_RECTANGLE_IN)
+
+ if (node->cache)
{
- /* This node is cached and the cache fulfills our need rect */
- context->cached = TRUE;
- gegl_operation_context_set_result_rect (context, &empty_rect);
+ gint i;
+ for (i = level; i >=0 && !context->cached; i--)
+ {
+ if (gegl_region_rect_in (node->cache->valid_region[level], request) == GEGL_OVERLAP_RECTANGLE_IN)
+ {
+ /* This node is cached and the cache fulfills our need rect */
+ context->cached = TRUE;
+ gegl_operation_context_set_result_rect (context, &empty_rect);
+ }
+ }
+ if (context->cached)
+ continue;
}
- else
- {
- /* Expand request if the operation has a minimum processing requirement */
- GeglRectangle full_request = gegl_operation_get_cached_region (operation, request);
- gegl_operation_context_set_need_rect (context, &full_request);
+ {
+ /* Expand request if the operation has a minimum processing requirement */
+ GeglRectangle full_request = gegl_operation_get_cached_region (operation, request);
- /* FIXME: We could trim this down based on the cache, instead of being all or nothing */
- gegl_operation_context_set_result_rect (context, request);
+ gegl_operation_context_set_need_rect (context, &full_request);
- for (input_pads = node->input_pads; input_pads; input_pads = input_pads->next)
- {
- GeglPad *source_pad = gegl_pad_get_connected_to (input_pads->data);
+ /* FIXME: We could trim this down based on the cache, instead of being all or nothing */
+ gegl_operation_context_set_result_rect (context, request);
- if (source_pad)
- {
- GeglNode *source_node = gegl_pad_get_node (source_pad);
- GeglOperationContext *source_context = g_hash_table_lookup (path->contexts, source_node);
- const gchar *pad_name = gegl_pad_get_name (input_pads->data);
+ for (input_pads = node->input_pads; input_pads; input_pads = input_pads->next)
+ {
+ GeglPad *source_pad = gegl_pad_get_connected_to (input_pads->data);
- GeglRectangle rect, current_need, new_need;
+ if (source_pad)
+ {
+ GeglNode *source_node = gegl_pad_get_node (source_pad);
+ GeglOperationContext *source_context = g_hash_table_lookup (path->contexts, source_node);
+ const gchar *pad_name = gegl_pad_get_name (input_pads->data);
- /* Combine this need rect with any existing request */
- rect = gegl_operation_get_required_for_output (operation, pad_name, &full_request);
- current_need = *gegl_operation_context_get_need_rect (source_context);
+ GeglRectangle rect, current_need, new_need;
- gegl_rectangle_bounding_box (&new_need, &rect, ¤t_need);
+ /* Combine this need rect with any existing request */
+ rect = gegl_operation_get_required_for_output (operation, pad_name, &full_request);
+ current_need = *gegl_operation_context_get_need_rect (source_context);
- /* Limit request to the nodes output */
- gegl_rectangle_intersect (&new_need, &source_node->have_rect, &new_need);
+ gegl_rectangle_bounding_box (&new_need, &rect, ¤t_need);
- gegl_operation_context_set_need_rect (source_context, &new_need);
- }
- }
- }
+ /* Limit request to the nodes output */
+ gegl_rectangle_intersect (&new_need, &source_node->have_rect, &new_need);
+
+ gegl_operation_context_set_need_rect (source_context, &new_need);
+ }
+ }
+ }
}
}
@@ -417,12 +429,12 @@ gegl_graph_process (GeglGraphTraversal *path,
gegl_operation_context_set_object (context, "input", G_OBJECT
(gegl_graph_get_shared_empty(path)));
}
- context->level = level; // XXX: get rid of context->level member?
+ context->level = level;
gegl_operation_process (operation, context, "output", &context->need_rect, context->level);
operation_result = GEGL_BUFFER (gegl_operation_context_get_object (context, "output"));
if (operation_result && operation_result == (GeglBuffer *)operation->node->cache)
- gegl_cache_computed (operation->node->cache, &context->need_rect);
+ gegl_cache_computed (operation->node->cache, &context->need_rect, level);
}
}
else
diff --git a/gegl/process/gegl-graph-traversal.h b/gegl/process/gegl-graph-traversal.h
index 413b2a0..20cbbc3 100644
--- a/gegl/process/gegl-graph-traversal.h
+++ b/gegl/process/gegl-graph-traversal.h
@@ -27,7 +27,8 @@ void gegl_graph_free (GeglGraphTraversal *path);
void gegl_graph_prepare (GeglGraphTraversal *path);
void gegl_graph_prepare_request (GeglGraphTraversal *path,
- const GeglRectangle *roi);
+ const GeglRectangle *roi,
+ gint level);
GeglBuffer *gegl_graph_process (GeglGraphTraversal *path,
gint level);
diff --git a/gegl/process/gegl-processor.c b/gegl/process/gegl-processor.c
index 6487d74..0f23bd9 100644
--- a/gegl/process/gegl-processor.c
+++ b/gegl/process/gegl-processor.c
@@ -483,10 +483,20 @@ render_rectangle (GeglProcessor *processor)
if (buffered)
{
- /* only do work if the rectangle is not completely inside the valid
- * region of the cache */
- if (gegl_region_rect_in (cache->valid_region, dr) !=
- GEGL_OVERLAP_RECTANGLE_IN)
+ gboolean found_full = FALSE;
+ for (gint level = processor->level; level >= 0; level--)
+ {
+ if (gegl_region_rect_in (cache->valid_region[level], dr) == GEGL_OVERLAP_RECTANGLE_IN)
+ {
+ found_full = TRUE;
+ break;
+ }
+ /* XXX: dr should be adjusted to be the bounding box of not-found
+ * in cache if there is partial hits
+ */
+ }
+
+ if (!found_full)
{
/* create a buffer and initialise it */
guchar *buf;
@@ -505,7 +515,7 @@ render_rectangle (GeglProcessor *processor)
gegl_buffer_set (GEGL_BUFFER (cache), dr, processor->level, format, buf, GEGL_AUTO_ROWSTRIDE);
/* tells the cache that the rectangle (dr) has been computed */
- gegl_cache_computed (cache, dr);
+ gegl_cache_computed (cache, dr, processor->level);
/* release the buffer */
g_free (buf);
@@ -593,7 +603,7 @@ gegl_processor_progress (GeglProcessor *processor)
}
else
{
- valid_region = gegl_node_get_cache (processor->input)->valid_region;
+ valid_region = gegl_node_get_cache (processor->input)->valid_region[processor->level];
}
wanted = rect_area (&(processor->rectangle));
@@ -633,7 +643,7 @@ gegl_processor_render (GeglProcessor *processor,
else
{
g_return_val_if_fail (processor->input != NULL, FALSE);
- valid_region = gegl_node_get_cache (processor->input)->valid_region;
+ valid_region = gegl_node_get_cache (processor->input)->valid_region[processor->level];
}
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]