[gegl] sampler: make size of cache in sampler base class adaptive
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] sampler: make size of cache in sampler base class adaptive
- Date: Tue, 17 Jun 2014 06:12:51 +0000 (UTC)
commit de26038e19883243fb465ddf290a05eb23d91bae
Author: Øyvind Kolås <pippin gimp org>
Date: Mon Jun 16 04:09:55 2014 +0200
sampler: make size of cache in sampler base class adaptive
Implement an adaptive caching policy; that meets the needs of affine
transformations. Running averages are kept of x/y deltas as well as the
magnitudes of the deltas of coordinates leading to cache misses.
The initial rectangle used is a small one; subsequent rectangles have extents
up to 64 pixels wide/tall; when tracked deltas are more diagonal than axis
aligned smaller more square regions are tracked.
gegl/buffer/gegl-buffer.h | 10 +
gegl/buffer/gegl-sampler-cubic.c | 8 +-
gegl/buffer/gegl-sampler-linear.c | 8 +-
gegl/buffer/gegl-sampler-lohalo.c | 89 +++++----
gegl/buffer/gegl-sampler-nearest.c | 8 +-
gegl/buffer/gegl-sampler-nohalo.c | 89 +++++----
gegl/buffer/gegl-sampler.c | 356 +++++++++++++-----------------------
gegl/buffer/gegl-sampler.h | 167 ++++++++++-------
perf/test-rotate.c | 2 +-
9 files changed, 348 insertions(+), 389 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer.h b/gegl/buffer/gegl-buffer.h
index 5b7b982..e07e4f3 100644
--- a/gegl/buffer/gegl-buffer.h
+++ b/gegl/buffer/gegl-buffer.h
@@ -442,6 +442,16 @@ void gegl_buffer_sample_cleanup (GeglBuffer *buffer);
*/
GeglSamplerType gegl_sampler_type_from_string (const gchar *string);
+typedef void (*GeglSamplerGetFun) (GeglSampler *self,
+ gdouble x,
+ gdouble y,
+ GeglMatrix2 *scale,
+ void *output,
+ GeglAbyssPolicy repeat_mode);
+
+GeglSamplerGetFun gegl_sampler_get_fun (GeglSampler *sampler);
+
+
/**
* gegl_buffer_sampler_new: (skip)
* @buffer: buffer to create a new sampler for
diff --git a/gegl/buffer/gegl-sampler-cubic.c b/gegl/buffer/gegl-sampler-cubic.c
index 96824f3..156a327 100644
--- a/gegl/buffer/gegl-sampler-cubic.c
+++ b/gegl/buffer/gegl-sampler-cubic.c
@@ -113,10 +113,10 @@ gegl_sampler_cubic_init (GeglSamplerCubic *self)
* right into left, and if the context_rect does not stretch far
* enough on the left, pixel lookups will fail.
*/
- GEGL_SAMPLER (self)->context_rect[0].x = -2;
- GEGL_SAMPLER (self)->context_rect[0].y = -2;
- GEGL_SAMPLER (self)->context_rect[0].width = 5;
- GEGL_SAMPLER (self)->context_rect[0].height = 5;
+ GEGL_SAMPLER (self)->level[0].context_rect.x = -2;
+ GEGL_SAMPLER (self)->level[0].context_rect.y = -2;
+ GEGL_SAMPLER (self)->level[0].context_rect.width = 5;
+ GEGL_SAMPLER (self)->level[0].context_rect.height = 5;
GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
self->b=1.0;
diff --git a/gegl/buffer/gegl-sampler-linear.c b/gegl/buffer/gegl-sampler-linear.c
index 8f415e7..92a881f 100644
--- a/gegl/buffer/gegl-sampler-linear.c
+++ b/gegl/buffer/gegl-sampler-linear.c
@@ -66,10 +66,10 @@ gegl_sampler_linear_class_init (GeglSamplerLinearClass *klass)
static void
gegl_sampler_linear_init (GeglSamplerLinear *self)
{
- GEGL_SAMPLER (self)->context_rect[0].x = -1 - LINEAR_EXTRA_ELBOW_ROOM;
- GEGL_SAMPLER (self)->context_rect[0].y = -1 - LINEAR_EXTRA_ELBOW_ROOM;
- GEGL_SAMPLER (self)->context_rect[0].width = 3 + 2*LINEAR_EXTRA_ELBOW_ROOM;
- GEGL_SAMPLER (self)->context_rect[0].height = 3 + 2*LINEAR_EXTRA_ELBOW_ROOM;
+ GEGL_SAMPLER (self)->level[0].context_rect.x = -1 - LINEAR_EXTRA_ELBOW_ROOM;
+ GEGL_SAMPLER (self)->level[0].context_rect.y = -1 - LINEAR_EXTRA_ELBOW_ROOM;
+ GEGL_SAMPLER (self)->level[0].context_rect.width = 3 + 2*LINEAR_EXTRA_ELBOW_ROOM;
+ GEGL_SAMPLER (self)->level[0].context_rect.height = 3 + 2*LINEAR_EXTRA_ELBOW_ROOM;
GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
}
diff --git a/gegl/buffer/gegl-sampler-lohalo.c b/gegl/buffer/gegl-sampler-lohalo.c
index 822c961..0acf80e 100644
--- a/gegl/buffer/gegl-sampler-lohalo.c
+++ b/gegl/buffer/gegl-sampler-lohalo.c
@@ -374,45 +374,56 @@ gegl_sampler_lohalo_class_init (GeglSamplerLohaloClass *klass)
static void
gegl_sampler_lohalo_init (GeglSamplerLohalo *self)
{
- GEGL_SAMPLER (self)->context_rect[0].x = -LOHALO_OFFSET_0;
- GEGL_SAMPLER (self)->context_rect[0].y = -LOHALO_OFFSET_0;
- GEGL_SAMPLER (self)->context_rect[0].width = LOHALO_SIZE_0;
- GEGL_SAMPLER (self)->context_rect[0].height = LOHALO_SIZE_0;
-
- GEGL_SAMPLER (self)->context_rect[1].x = -LOHALO_OFFSET_1;
- GEGL_SAMPLER (self)->context_rect[1].y = -LOHALO_OFFSET_1;
- GEGL_SAMPLER (self)->context_rect[1].width = LOHALO_SIZE_1;
- GEGL_SAMPLER (self)->context_rect[1].height = LOHALO_SIZE_1;
-
- GEGL_SAMPLER (self)->context_rect[2].x = -LOHALO_OFFSET_2;
- GEGL_SAMPLER (self)->context_rect[2].y = -LOHALO_OFFSET_2;
- GEGL_SAMPLER (self)->context_rect[2].width = LOHALO_SIZE_2;
- GEGL_SAMPLER (self)->context_rect[2].height = LOHALO_SIZE_2;
-
- GEGL_SAMPLER (self)->context_rect[3].x = -LOHALO_OFFSET_3;
- GEGL_SAMPLER (self)->context_rect[3].y = -LOHALO_OFFSET_3;
- GEGL_SAMPLER (self)->context_rect[3].width = LOHALO_SIZE_3;
- GEGL_SAMPLER (self)->context_rect[3].height = LOHALO_SIZE_3;
-
- GEGL_SAMPLER (self)->context_rect[4].x = -LOHALO_OFFSET_4;
- GEGL_SAMPLER (self)->context_rect[4].y = -LOHALO_OFFSET_4;
- GEGL_SAMPLER (self)->context_rect[4].width = LOHALO_SIZE_4;
- GEGL_SAMPLER (self)->context_rect[4].height = LOHALO_SIZE_4;
-
- GEGL_SAMPLER (self)->context_rect[5].x = -LOHALO_OFFSET_5;
- GEGL_SAMPLER (self)->context_rect[5].y = -LOHALO_OFFSET_5;
- GEGL_SAMPLER (self)->context_rect[5].width = LOHALO_SIZE_5;
- GEGL_SAMPLER (self)->context_rect[5].height = LOHALO_SIZE_5;
-
- GEGL_SAMPLER (self)->context_rect[6].x = -LOHALO_OFFSET_6;
- GEGL_SAMPLER (self)->context_rect[6].y = -LOHALO_OFFSET_6;
- GEGL_SAMPLER (self)->context_rect[6].width = LOHALO_SIZE_6;
- GEGL_SAMPLER (self)->context_rect[6].height = LOHALO_SIZE_6;
-
- GEGL_SAMPLER (self)->context_rect[7].x = -LOHALO_OFFSET_7;
- GEGL_SAMPLER (self)->context_rect[7].y = -LOHALO_OFFSET_7;
- GEGL_SAMPLER (self)->context_rect[7].width = LOHALO_SIZE_7;
- GEGL_SAMPLER (self)->context_rect[7].height = LOHALO_SIZE_7;
+ GeglSampler *sampler = GEGL_SAMPLER (self);
+ GeglSamplerLevel *level;
+
+ level = &sampler->level[0];
+ level->context_rect.x = -LOHALO_OFFSET_0;
+ level->context_rect.y = -LOHALO_OFFSET_0;
+ level->context_rect.width = LOHALO_SIZE_0;
+ level->context_rect.height = LOHALO_SIZE_0;
+
+ level = &sampler->level[1];
+ level->context_rect.x = -LOHALO_OFFSET_1;
+ level->context_rect.y = -LOHALO_OFFSET_1;
+ level->context_rect.width = LOHALO_SIZE_1;
+ level->context_rect.height = LOHALO_SIZE_1;
+
+ level = &sampler->level[2];
+ level->context_rect.x = -LOHALO_OFFSET_2;
+ level->context_rect.y = -LOHALO_OFFSET_2;
+ level->context_rect.width = LOHALO_SIZE_2;
+ level->context_rect.height = LOHALO_SIZE_2;
+
+ level = &sampler->level[3];
+ level->context_rect.x = -LOHALO_OFFSET_3;
+ level->context_rect.y = -LOHALO_OFFSET_3;
+ level->context_rect.width = LOHALO_SIZE_3;
+ level->context_rect.height = LOHALO_SIZE_3;
+
+ level = &sampler->level[4];
+ level->context_rect.x = -LOHALO_OFFSET_4;
+ level->context_rect.y = -LOHALO_OFFSET_4;
+ level->context_rect.width = LOHALO_SIZE_4;
+ level->context_rect.height = LOHALO_SIZE_4;
+
+ level = &sampler->level[5];
+ level->context_rect.x = -LOHALO_OFFSET_5;
+ level->context_rect.y = -LOHALO_OFFSET_5;
+ level->context_rect.width = LOHALO_SIZE_5;
+ level->context_rect.height = LOHALO_SIZE_5;
+
+ level = &sampler->level[6];
+ level->context_rect.x = -LOHALO_OFFSET_6;
+ level->context_rect.y = -LOHALO_OFFSET_6;
+ level->context_rect.width = LOHALO_SIZE_6;
+ level->context_rect.height = LOHALO_SIZE_6;
+
+ level = &sampler->level[7];
+ level->context_rect.x = -LOHALO_OFFSET_7;
+ level->context_rect.y = -LOHALO_OFFSET_7;
+ level->context_rect.width = LOHALO_SIZE_7;
+ level->context_rect.height = LOHALO_SIZE_7;
GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
}
diff --git a/gegl/buffer/gegl-sampler-nearest.c b/gegl/buffer/gegl-sampler-nearest.c
index 865cb88..e40a495 100644
--- a/gegl/buffer/gegl-sampler-nearest.c
+++ b/gegl/buffer/gegl-sampler-nearest.c
@@ -65,10 +65,10 @@ gegl_sampler_nearest_class_init (GeglSamplerNearestClass *klass)
static void
gegl_sampler_nearest_init (GeglSamplerNearest *self)
{
- GEGL_SAMPLER (self)->context_rect[0].x = 0;
- GEGL_SAMPLER (self)->context_rect[0].y = 0;
- GEGL_SAMPLER (self)->context_rect[0].width = 1;
- GEGL_SAMPLER (self)->context_rect[0].height = 1;
+ GEGL_SAMPLER (self)->level[0].context_rect.x = 0;
+ GEGL_SAMPLER (self)->level[0].context_rect.y = 0;
+ GEGL_SAMPLER (self)->level[0].context_rect.width = 1;
+ GEGL_SAMPLER (self)->level[0].context_rect.height = 1;
GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
}
diff --git a/gegl/buffer/gegl-sampler-nohalo.c b/gegl/buffer/gegl-sampler-nohalo.c
index 0c49c4d..eeef4af 100644
--- a/gegl/buffer/gegl-sampler-nohalo.c
+++ b/gegl/buffer/gegl-sampler-nohalo.c
@@ -457,45 +457,56 @@ gegl_sampler_nohalo_class_init (GeglSamplerNohaloClass *klass)
static void
gegl_sampler_nohalo_init (GeglSamplerNohalo *self)
{
- GEGL_SAMPLER (self)->context_rect[0].x = -NOHALO_OFFSET_0;
- GEGL_SAMPLER (self)->context_rect[0].y = -NOHALO_OFFSET_0;
- GEGL_SAMPLER (self)->context_rect[0].width = NOHALO_SIZE_0;
- GEGL_SAMPLER (self)->context_rect[0].height = NOHALO_SIZE_0;
-
- GEGL_SAMPLER (self)->context_rect[1].x = -NOHALO_OFFSET_1;
- GEGL_SAMPLER (self)->context_rect[1].y = -NOHALO_OFFSET_1;
- GEGL_SAMPLER (self)->context_rect[1].width = NOHALO_SIZE_1;
- GEGL_SAMPLER (self)->context_rect[1].height = NOHALO_SIZE_1;
-
- GEGL_SAMPLER (self)->context_rect[2].x = -NOHALO_OFFSET_2;
- GEGL_SAMPLER (self)->context_rect[2].y = -NOHALO_OFFSET_2;
- GEGL_SAMPLER (self)->context_rect[2].width = NOHALO_SIZE_2;
- GEGL_SAMPLER (self)->context_rect[2].height = NOHALO_SIZE_2;
-
- GEGL_SAMPLER (self)->context_rect[3].x = -NOHALO_OFFSET_3;
- GEGL_SAMPLER (self)->context_rect[3].y = -NOHALO_OFFSET_3;
- GEGL_SAMPLER (self)->context_rect[3].width = NOHALO_SIZE_3;
- GEGL_SAMPLER (self)->context_rect[3].height = NOHALO_SIZE_3;
-
- GEGL_SAMPLER (self)->context_rect[4].x = -NOHALO_OFFSET_4;
- GEGL_SAMPLER (self)->context_rect[4].y = -NOHALO_OFFSET_4;
- GEGL_SAMPLER (self)->context_rect[4].width = NOHALO_SIZE_4;
- GEGL_SAMPLER (self)->context_rect[4].height = NOHALO_SIZE_4;
-
- GEGL_SAMPLER (self)->context_rect[5].x = -NOHALO_OFFSET_5;
- GEGL_SAMPLER (self)->context_rect[5].y = -NOHALO_OFFSET_5;
- GEGL_SAMPLER (self)->context_rect[5].width = NOHALO_SIZE_5;
- GEGL_SAMPLER (self)->context_rect[5].height = NOHALO_SIZE_5;
-
- GEGL_SAMPLER (self)->context_rect[6].x = -NOHALO_OFFSET_6;
- GEGL_SAMPLER (self)->context_rect[6].y = -NOHALO_OFFSET_6;
- GEGL_SAMPLER (self)->context_rect[6].width = NOHALO_SIZE_6;
- GEGL_SAMPLER (self)->context_rect[6].height = NOHALO_SIZE_6;
-
- GEGL_SAMPLER (self)->context_rect[7].x = -NOHALO_OFFSET_7;
- GEGL_SAMPLER (self)->context_rect[7].y = -NOHALO_OFFSET_7;
- GEGL_SAMPLER (self)->context_rect[7].width = NOHALO_SIZE_7;
- GEGL_SAMPLER (self)->context_rect[7].height = NOHALO_SIZE_7;
+ GeglSampler *sampler = GEGL_SAMPLER (self);
+ GeglSamplerLevel *level;
+
+ level = &sampler->level[0];
+ level->context_rect.x = -NOHALO_OFFSET_0;
+ level->context_rect.y = -NOHALO_OFFSET_0;
+ level->context_rect.width = NOHALO_SIZE_0;
+ level->context_rect.height = NOHALO_SIZE_0;
+
+ level = &sampler->level[1];
+ level->context_rect.x = -NOHALO_OFFSET_1;
+ level->context_rect.y = -NOHALO_OFFSET_1;
+ level->context_rect.width = NOHALO_SIZE_1;
+ level->context_rect.height = NOHALO_SIZE_1;
+
+ level = &sampler->level[2];
+ level->context_rect.x = -NOHALO_OFFSET_2;
+ level->context_rect.y = -NOHALO_OFFSET_2;
+ level->context_rect.width = NOHALO_SIZE_2;
+ level->context_rect.height = NOHALO_SIZE_2;
+
+ level = &sampler->level[3];
+ level->context_rect.x = -NOHALO_OFFSET_3;
+ level->context_rect.y = -NOHALO_OFFSET_3;
+ level->context_rect.width = NOHALO_SIZE_3;
+ level->context_rect.height = NOHALO_SIZE_3;
+
+ level = &sampler->level[4];
+ level->context_rect.x = -NOHALO_OFFSET_4;
+ level->context_rect.y = -NOHALO_OFFSET_4;
+ level->context_rect.width = NOHALO_SIZE_4;
+ level->context_rect.height = NOHALO_SIZE_4;
+
+ level = &sampler->level[5];
+ level->context_rect.x = -NOHALO_OFFSET_5;
+ level->context_rect.y = -NOHALO_OFFSET_5;
+ level->context_rect.width = NOHALO_SIZE_5;
+ level->context_rect.height = NOHALO_SIZE_5;
+
+ level = &sampler->level[6];
+ level->context_rect.x = -NOHALO_OFFSET_6;
+ level->context_rect.y = -NOHALO_OFFSET_6;
+ level->context_rect.width = NOHALO_SIZE_6;
+ level->context_rect.height = NOHALO_SIZE_6;
+
+ level = &sampler->level[7];
+ level->context_rect.x = -NOHALO_OFFSET_7;
+ level->context_rect.y = -NOHALO_OFFSET_7;
+ level->context_rect.width = NOHALO_SIZE_7;
+ level->context_rect.height = NOHALO_SIZE_7;
GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
}
diff --git a/gegl/buffer/gegl-sampler.c b/gegl/buffer/gegl-sampler.c
index 755160e..224f520 100644
--- a/gegl/buffer/gegl-sampler.c
+++ b/gegl/buffer/gegl-sampler.c
@@ -110,17 +110,21 @@ gegl_sampler_class_init (GeglSamplerClass *klass)
}
static void
-gegl_sampler_init (GeglSampler *self)
+gegl_sampler_init (GeglSampler *sampler)
{
- int i = 0;
- self->buffer = NULL;
+ gint i = 0;
+ sampler->buffer = NULL;
do {
GeglRectangle context_rect = {0,0,1,1};
GeglRectangle sampler_rectangle = {0,0,0,0};
- self->sampler_buffer[i] = NULL;
- self->context_rect[i] = context_rect;
- self->sampler_rectangle[i] = sampler_rectangle;
+ sampler->level[i].sampler_buffer = NULL;
+ sampler->level[i].context_rect = context_rect;
+ sampler->level[i].sampler_rectangle = sampler_rectangle;
} while ( ++i<GEGL_SAMPLER_MIPMAP_LEVELS );
+
+ sampler->level[0].sampler_buffer =
+ g_malloc0 (GEGL_SAMPLER_MAXIMUM_WIDTH *
+ GEGL_SAMPLER_MAXIMUM_HEIGHT * 16);
}
void
@@ -158,17 +162,9 @@ gegl_sampler_prepare (GeglSampler *self)
* This makes the cache rect invalid, in case the data in the buffer
* has changed:
*/
- self->sampler_rectangle[0].width = 0;
- self->sampler_rectangle[0].height = 0;
+ self->level[0].sampler_rectangle.width = 0;
+ self->level[0].sampler_rectangle.height = 0;
-#if 0
- if (self->cache_buffer) /* Force a regetting of the region, even
- though the cached getter may be valid. */
- {
- g_free (self->cache_buffer);
- self->cache_buffer = NULL;
- }
-#endif
self->get = klass->get; /* cache the sampler in the instance */
}
@@ -191,10 +187,10 @@ finalize (GObject *gobject)
GeglSampler *sampler = GEGL_SAMPLER (gobject);
int i = 0;
do {
- if (sampler->sampler_buffer[i])
+ if (sampler->level[i].sampler_buffer)
{
- g_free (sampler->sampler_buffer[i]);
- sampler->sampler_buffer[i] = NULL;
+ g_free (sampler->level[i].sampler_buffer);
+ sampler->level[i].sampler_buffer = NULL;
}
} while ( ++i<GEGL_SAMPLER_MIPMAP_LEVELS );
G_OBJECT_CLASS (gegl_sampler_parent_class)->finalize (gobject);
@@ -211,254 +207,151 @@ dispose (GObject *gobject)
G_OBJECT_CLASS (gegl_sampler_parent_class)->dispose (gobject);
}
-/*
- * Gets a pointer to the center pixel, within a buffer that has a
- * rowstride of GEGL_SAMPLER_MAXIMUM_WIDTH px * bpp.
- */
-gfloat *
-gegl_sampler_get_ptr (GeglSampler *const sampler,
- const gint x,
- const gint y,
- GeglAbyssPolicy repeat_mode)
+GeglRectangle _gegl_sampler_compute_rectangle (GeglSampler *sampler,
+ gint x,
+ gint y,
+ gint level_no)
{
- guchar *buffer_ptr;
- gint dx;
- gint dy;
- gint sof;
+ GeglRectangle rectangle;
+ GeglSamplerLevel *level = &sampler->level[level_no];
- const gint bpp =
- babl_format_get_bytes_per_pixel (sampler->interpolate_format);
+ if (level->last_x || level->last_y)
+ {
+ gint x_delta = x - level->last_x;
+ gint y_delta = y - level->last_y;
+ gint max_delta_squared = 60 * 60;
- const gint maximum_width = GEGL_SAMPLER_MAXIMUM_WIDTH;
- const gint maximum_height = GEGL_SAMPLER_MAXIMUM_HEIGHT;
- g_assert (sampler->context_rect[0].width <= maximum_width);
- g_assert (sampler->context_rect[0].height <= maximum_height);
-
- if ((sampler->sampler_buffer[0] == NULL)
- ||
- (x + sampler->context_rect[0].x < sampler->sampler_rectangle[0].x)
- ||
- (y + sampler->context_rect[0].y < sampler->sampler_rectangle[0].y)
- ||
- (x + sampler->context_rect[0].x + sampler->context_rect[0].width >
- sampler->sampler_rectangle[0].x + sampler->sampler_rectangle[0].width)
- ||
- (y + sampler->context_rect[0].y + sampler->context_rect[0].height >
- sampler->sampler_rectangle[0].y + sampler->sampler_rectangle[0].height))
+ if (x_delta * x_delta < max_delta_squared &&
+ y_delta * y_delta < max_delta_squared)
{
- /*
- * fetch_rectangle will become the value of
- * sampler->sampler_rectangle[0]:
- */
- GeglRectangle fetch_rectangle;
-
- /*
- * Always request the same amount of pixels:
- */
- if (sampler->sampler_buffer[0] == NULL)
- {
- sampler->sampler_buffer[0] =
- g_malloc0 (maximum_width * maximum_height * bpp);
- }
-
- /*
- * Override the fetch rectangle needed by the sampler in order
- * to prevent constant buffer creation, adding some elbow room
- * at the top and left so that buffers are not constantly
- * re-created when things are "slanted the wrong way", taking
- * into account that it is more likely that further access is to
- * the right or down of our currently requested
- * position. Consequently, we move the top left corner of the
- * context_rect, which has the effect of leaving elbow room there.
- *
- * Note that transform-core now works hard to have scanlines go
- * toward the interior of the buffer.
- *
- * For operations like resize and left-right and top-bottom
- * reflections, there is no reason to add elbow room. This means
- * that the following code will need to have a dual personality
- * sooner or later. Eliminating the elbow room for such
- * operations (and making tiles elongated rectangles) gives a
- * big speedup.
- */
- fetch_rectangle.width = maximum_width;
- fetch_rectangle.height = maximum_height;
- fetch_rectangle.x =
- x + sampler->context_rect[0].x -
- (maximum_width - sampler->context_rect[0].width ) / (gint) 4;
- fetch_rectangle.y =
- y + sampler->context_rect[0].y -
- (maximum_height - sampler->context_rect[0].height) / (gint) 4;
-
- gegl_buffer_get (sampler->buffer,
- &fetch_rectangle,
- 1.0,
- sampler->interpolate_format,
- sampler->sampler_buffer[0],
- GEGL_AUTO_ROWSTRIDE,
- repeat_mode);
-
- sampler->sampler_rectangle[0] = fetch_rectangle;
+ level->x_delta = level->x_delta * 0.99 + x_delta * 0.01;
+ level->y_delta = level->y_delta * 0.99 + y_delta * 0.01;
+ if (x_delta < 0) x_delta = -x_delta;
+ if (y_delta < 0) y_delta = -y_delta;
+ level->x_magnitude = level->x_magnitude * 0.99 + x_delta * 0.01;
+ level->y_magnitude = level->y_magnitude * 0.99 + y_delta * 0.01;
}
+ }
+ level->last_x = x;
+ level->last_y = y;
- dx = x - sampler->sampler_rectangle[0].x;
- dy = y - sampler->sampler_rectangle[0].y;
- buffer_ptr = (guchar *)sampler->sampler_buffer[0];
- sof = ( dx + dy * sampler->sampler_rectangle[0].width ) * bpp;
-
- return (gfloat*)(buffer_ptr+sof);
-}
+ if (level->x_magnitude > 0.001 || level->y_magnitude > 0.001)
+ {
+ gfloat magnitude = sqrtf (level->x_magnitude * level->x_magnitude +
+ level->y_magnitude * level->y_magnitude);
+ gfloat new_magnitude;
-gfloat *
-gegl_sampler_get_from_buffer (GeglSampler *const sampler,
- const gint x,
- const gint y,
- GeglAbyssPolicy repeat_mode)
-{
- guchar *buffer_ptr;
- gint dx;
- gint dy;
- gint sof;
+ if (level->x_magnitude > level->y_magnitude)
+ new_magnitude =
+ 4 + 60 * (level->x_magnitude - level->y_magnitude) / level->x_magnitude;
+ else
+ new_magnitude =
+ 4 + 60 * (level->y_magnitude - level->x_magnitude) / level->y_magnitude;
+
+ rectangle.width =
+ (level->x_magnitude / magnitude) * new_magnitude
+ + level->context_rect.width + 2;
+ rectangle.height =
+ (level->y_magnitude / magnitude) * new_magnitude
+ + level->context_rect.height + 2;
+
+ /* todo: if both xmag and ymag are small - but similar in magnitude
+ we should increase the size of the cache if it would fit, thus
+ perhaps working better on small local non-linear access patterns
+ */
- const gint bpp =
- babl_format_get_bytes_per_pixel (sampler->interpolate_format);
+ if (rectangle.width >= GEGL_SAMPLER_MAXIMUM_WIDTH)
+ rectangle.width = GEGL_SAMPLER_MAXIMUM_WIDTH;
+ if (rectangle.height >= GEGL_SAMPLER_MAXIMUM_HEIGHT)
+ rectangle.height = GEGL_SAMPLER_MAXIMUM_HEIGHT;
- const gint maximum_width = GEGL_SAMPLER_MAXIMUM_WIDTH;
- const gint maximum_height = GEGL_SAMPLER_MAXIMUM_HEIGHT;
- g_assert (sampler->context_rect[0].width <= maximum_width);
- g_assert (sampler->context_rect[0].height <= maximum_height);
-
- if ((sampler->sampler_buffer[0] == NULL)
- ||
- (x < sampler->sampler_rectangle[0].x)
- ||
- (y < sampler->sampler_rectangle[0].y)
- ||
- (x >=
- sampler->sampler_rectangle[0].x + sampler->sampler_rectangle[0].width)
- ||
- (y >=
- sampler->sampler_rectangle[0].y + sampler->sampler_rectangle[0].height))
- {
- /*
- * fetch_rectangle will become the value of
- * sampler->sampler_rectangle:
- */
- GeglRectangle fetch_rectangle;
- /*
- * Always request the same amount of pixels:
+ /* align rectangle corner we've likely entered with sampled pixel
*/
- if (sampler->sampler_buffer[0] == NULL)
- {
- sampler->sampler_buffer[0] =
- g_malloc0 (maximum_width * maximum_height * bpp);
- }
-
- fetch_rectangle.width = maximum_width;
- fetch_rectangle.height = maximum_height;
- fetch_rectangle.x = x -
- (maximum_width - sampler->context_rect[0].width ) / (gint) 4;
- fetch_rectangle.y = y -
- (maximum_height - sampler->context_rect[0].height) / (gint) 4;
+ if (level->x_delta >=0)
+ rectangle.x = x + level->context_rect.x
+ - (rectangle.width - level->context_rect.x)/10;
+ else
+ rectangle.x = x + level->context_rect.x
+ - (rectangle.width - level->context_rect.width) * 9/10;
- gegl_buffer_get (sampler->buffer,
- &fetch_rectangle,
- 1.0,
- sampler->interpolate_format,
- sampler->sampler_buffer[0],
- GEGL_AUTO_ROWSTRIDE,
- repeat_mode);
+ if (level->y_delta >=0)
+ rectangle.y = y + level->context_rect.y
+ - (rectangle.height - level->context_rect.y)/10;
+ else
+ rectangle.y = y + level->context_rect.y
+ - (rectangle.height - level->context_rect.height) * 9/10;
+ }
+ else
+ {
+ rectangle.width = level->context_rect.width + 2;
+ rectangle.height = level->context_rect.height + 2;
- sampler->sampler_rectangle[0] = fetch_rectangle;
+ rectangle.x = x + level->context_rect.x
+ - (rectangle.width - level->context_rect.x)/4;
+ rectangle.y = y + level->context_rect.y
+ - (rectangle.height - level->context_rect.y)/4;
}
- dx = x - sampler->sampler_rectangle[0].x;
- dy = y - sampler->sampler_rectangle[0].y;
- buffer_ptr = (guchar *)sampler->sampler_buffer[0];
- sof = ( dx + dy * sampler->sampler_rectangle[0].width ) * bpp;
+ g_assert (level->context_rect.width <= rectangle.width);
+ g_assert (level->context_rect.height <= rectangle.height);
- return (gfloat*)(buffer_ptr+sof);
+ return rectangle;
}
+
gfloat *
-gegl_sampler_get_from_mipmap (GeglSampler *const sampler,
- const gint x,
- const gint y,
- const gint level,
- GeglAbyssPolicy repeat_mode)
+gegl_sampler_get_from_mipmap (GeglSampler *sampler,
+ gint x,
+ gint y,
+ gint level_no,
+ GeglAbyssPolicy repeat_mode)
{
+ GeglSamplerLevel *level = &sampler->level[level_no];
guchar *buffer_ptr;
gint dx;
gint dy;
gint sof;
- const gdouble scale = 1. / ( (gdouble) (1<<level) );
-
- const gint bpp =
- babl_format_get_bytes_per_pixel (sampler->interpolate_format);
+ const gdouble scale = 1. / ( (gdouble) (1<<level_no) );
const gint maximum_width = GEGL_SAMPLER_MAXIMUM_WIDTH;
const gint maximum_height = GEGL_SAMPLER_MAXIMUM_HEIGHT;
- g_assert (level >= 0 && level < GEGL_SAMPLER_MIPMAP_LEVELS);
- g_assert (sampler->context_rect[level].width <= maximum_width);
- g_assert (sampler->context_rect[level].height <= maximum_height);
-
- if ((sampler->sampler_buffer[level] == NULL)
- ||
- (x + sampler->context_rect[level].x < sampler->sampler_rectangle[level].x)
- ||
- (y + sampler->context_rect[level].y < sampler->sampler_rectangle[level].y)
- ||
- (x + sampler->context_rect[level].x +
- sampler->context_rect[level].width >
- sampler->sampler_rectangle[level].x +
- sampler->sampler_rectangle[level].width)
- ||
- (y + sampler->context_rect[level].y +
- sampler->context_rect[level].height >
- sampler->sampler_rectangle[level].y +
- sampler->sampler_rectangle[level].height))
+ g_assert (level_no >= 0 && level_no < GEGL_SAMPLER_MIPMAP_LEVELS);
+ g_assert (level->context_rect.width <= maximum_width);
+ g_assert (level->context_rect.height <= maximum_height);
+
+ if ((level->sampler_buffer == NULL)
+ || (x + level->context_rect.x < level->sampler_rectangle.x)
+ || (y + level->context_rect.y < level->sampler_rectangle.y)
+ || (x + level->context_rect.x + level->context_rect.width
+ > level->sampler_rectangle.x + level->sampler_rectangle.width)
+ || (y + level->context_rect.y + level->context_rect.height
+ > level->sampler_rectangle.y + level->sampler_rectangle.height))
{
/*
* fetch_rectangle will become the value of
* sampler->sampler_rectangle[level]:
*/
- GeglRectangle fetch_rectangle;
+ level->sampler_rectangle = _gegl_sampler_compute_rectangle (sampler, x, y,
+ level_no);
- /*
- * Always request the same amount of pixels:
- */
- if (sampler->sampler_buffer[level] == NULL)
- {
- sampler->sampler_buffer[level] =
- g_malloc0 (maximum_width * maximum_height * bpp);
- }
-
- fetch_rectangle.width = maximum_width;
- fetch_rectangle.height = maximum_height;
- fetch_rectangle.x =
- x + sampler->context_rect[level].x -
- (maximum_width - sampler->context_rect[level].width ) / (gint) 4;
- fetch_rectangle.y =
- y + sampler->context_rect[level].y -
- (maximum_height - sampler->context_rect[level].height) / (gint) 4;
+ level->sampler_buffer =
+ g_malloc0 (GEGL_SAMPLER_ROWSTRIDE * GEGL_SAMPLER_MAXIMUM_HEIGHT);
gegl_buffer_get (sampler->buffer,
- &fetch_rectangle,
+ &level->sampler_rectangle,
scale,
sampler->interpolate_format,
- sampler->sampler_buffer[level],
- GEGL_AUTO_ROWSTRIDE,
+ level->sampler_buffer,
+ GEGL_SAMPLER_ROWSTRIDE,
repeat_mode);
-
- sampler->sampler_rectangle[level] = fetch_rectangle;
}
- dx = x - sampler->sampler_rectangle[level].x;
- dy = y - sampler->sampler_rectangle[level].y;
- buffer_ptr = (guchar *)sampler->sampler_buffer[level];
- sof = ( dx + dy * sampler->sampler_rectangle[level].width ) * bpp;
+ dx = x - level->sampler_rectangle.x;
+ dy = y - level->sampler_rectangle.y;
+ buffer_ptr = (guchar *)level->sampler_buffer;
+ sof = ( dx + dy * GEGL_SAMPLER_MAXIMUM_WIDTH) * GEGL_SAMPLER_BPP;
return (gfloat*)(buffer_ptr+sof);
}
@@ -604,7 +497,7 @@ gegl_buffer_sampler_new (GeglBuffer *buffer,
const GeglRectangle*
gegl_sampler_get_context_rect (GeglSampler *sampler)
{
- return &(sampler->context_rect[0]);
+ return &(sampler->level[0].context_rect);
}
static void
@@ -613,6 +506,7 @@ buffer_contents_changed (GeglBuffer *buffer,
gpointer userdata)
{
GeglSampler *self = GEGL_SAMPLER (userdata);
+ int i;
/*
* Invalidate all mipmap levels by setting the width and height of the
@@ -621,7 +515,13 @@ buffer_contents_changed (GeglBuffer *buffer,
* XXX: it might be faster to only invalidate rects that intersect
* changed_rect
*/
- memset (self->sampler_rectangle, 0, sizeof (self->sampler_rectangle));
+ for (i = 0; i < GEGL_SAMPLER_MIPMAP_LEVELS; i++)
+ memset (&self->level[i].sampler_rectangle, 0, sizeof (self->level[0].sampler_rectangle));
return;
}
+
+GeglSamplerGetFun gegl_sampler_get_fun (GeglSampler *sampler)
+{
+ return sampler->get;
+}
diff --git a/gegl/buffer/gegl-sampler.h b/gegl/buffer/gegl-sampler.h
index 69f9f64..6efeb5a 100644
--- a/gegl/buffer/gegl-sampler.h
+++ b/gegl/buffer/gegl-sampler.h
@@ -40,101 +40,128 @@ G_BEGIN_DECLS
* twice as wide as they are tall.
*/
-//128 20.42 23.23
-// 96 26.91 30.39
-// 64 34.32 41.52
-// 48 38.66 46.67
-// 32 43.17 53.78
-// 24 45.38 56.11
-// 20 45.18 56.70
-// 20 45.41 56.32
-// 19 45.75 57.81
-// 19 45.81 57.69
-// 18 47.16 60.02
-// 18 47.19 60.36
-// 17 46.43 58.73
-// 17 46.61 58.85
-// 16 46.44 58.73
-// 8 43.25 54
-// 4 33.11 39
-
-#define GEGL_SAMPLER_MAXIMUM_HEIGHT (27)
+#define GEGL_SAMPLER_MAXIMUM_HEIGHT (64)
#define GEGL_SAMPLER_MAXIMUM_WIDTH (GEGL_SAMPLER_MAXIMUM_HEIGHT)
+#define GEGL_SAMPLER_BPP 16
+#define GEGL_SAMPLER_ROWSTRIDE (GEGL_SAMPLER_MAXIMUM_WIDTH * GEGL_SAMPLER_BPP)
typedef struct _GeglSamplerClass GeglSamplerClass;
+typedef struct GeglSamplerLevel
+{
+ GeglRectangle context_rect;
+ gpointer sampler_buffer;
+ GeglRectangle sampler_rectangle;
+
+ gint last_x;
+ gint last_y;
+ float x_delta;
+ float y_delta;
+ float x_magnitude;
+ float y_magnitude;
+} GeglSamplerLevel;
+
struct _GeglSampler
{
- GObject parent_instance;
- void (* get) (GeglSampler *self,
- gdouble x,
- gdouble y,
- GeglMatrix2 *scale,
- void *output,
- GeglAbyssPolicy repeat_mode);
- /* we cache the getter in the instance, (being able to return the
- function pointer itself and cache it outside the calling loop
- would be even quicker.
- */
+ GObject parent_instance;
+ GeglSamplerGetFun get;
/*< private >*/
GeglBuffer *buffer;
const Babl *format;
const Babl *interpolate_format;
const Babl *fish;
- GeglRectangle context_rect[GEGL_SAMPLER_MIPMAP_LEVELS];
- gpointer sampler_buffer[GEGL_SAMPLER_MIPMAP_LEVELS];
- GeglRectangle sampler_rectangle[GEGL_SAMPLER_MIPMAP_LEVELS];
- gdouble x; /* mirrors the currently requested */
- gdouble y; /* coordinates in the instance */
- gpointer padding[8]; /* eat from the padding if adding to the struct */
+ GeglSamplerLevel level[GEGL_SAMPLER_MIPMAP_LEVELS];
};
+typedef void (*GeglSamplerGetFun) (GeglSampler *self,
+ gdouble x,
+ gdouble y,
+ GeglMatrix2 *scale,
+ void *output,
+ GeglAbyssPolicy repeat_mode);
+
struct _GeglSamplerClass
{
GObjectClass parent_class;
void (* prepare) (GeglSampler *self);
- void (* get) (GeglSampler *self,
- gdouble x,
- gdouble y,
- GeglMatrix2 *scale,
- void *output,
- GeglAbyssPolicy repeat_mode);
- void (*set_buffer) (GeglSampler *self,
- GeglBuffer *buffer);
-
- gpointer padding[8]; /* eat from the padding if adding to the struct */
+ GeglSamplerGetFun get;
+ void (*set_buffer) (GeglSampler *self,
+ GeglBuffer *buffer);
};
GType gegl_sampler_get_type (void) G_GNUC_CONST;
/* virtual method invokers */
-void gegl_sampler_prepare (GeglSampler *self);
-void gegl_sampler_set_buffer (GeglSampler *self,
- GeglBuffer *buffer);
-
-void gegl_sampler_get (GeglSampler *self,
- gdouble x,
- gdouble y,
- GeglMatrix2 *scale,
- void *output,
- GeglAbyssPolicy repeat_mode);
-
-gfloat * gegl_sampler_get_from_buffer (GeglSampler *const sampler,
- const gint x,
- const gint y,
- GeglAbyssPolicy repeat_mode);
-gfloat * gegl_sampler_get_from_mipmap (GeglSampler *const sampler,
- const gint x,
- const gint y,
- const gint level,
- GeglAbyssPolicy repeat_mode);
-gfloat * gegl_sampler_get_ptr (GeglSampler *const sampler,
- const gint x,
- const gint y,
- GeglAbyssPolicy repeat_mode);
+void gegl_sampler_prepare (GeglSampler *self);
+void gegl_sampler_set_buffer (GeglSampler *self,
+ GeglBuffer *buffer);
+
+GeglSamplerGetFun gegl_sampler_get_fun (GeglSampler *sampler);
+
+gfloat * gegl_sampler_get_from_buffer (GeglSampler *sampler,
+ gint x,
+ gint y,
+ GeglAbyssPolicy repeat_mode);
+gfloat * gegl_sampler_get_from_mipmap (GeglSampler *sampler,
+ gint x,
+ gint y,
+ gint level,
+ GeglAbyssPolicy repeat_mode);
+gfloat * _gegl_sampler_get_ptr (GeglSampler *sampler,
+ gint x,
+ gint y,
+ GeglAbyssPolicy repeat_mode);
+
+GeglRectangle _gegl_sampler_compute_rectangle (GeglSampler *sampler,
+ gint x,
+ gint y,
+ gint level);
+
+/*
+ * Gets a pointer to the center pixel, within a buffer that has a
+ * rowstride of GEGL_SAMPLER_MAXIMUM_WIDTH * 16 (16 is the bpp of RaGaBaA
+ * float).
+ *
+ * inlining this function gives a 4-5% performance gain for affine ops for
+ * linear/cubic sampling.
+ */
+static inline gfloat *
+gegl_sampler_get_ptr (GeglSampler *sampler,
+ gint x,
+ gint y,
+ GeglAbyssPolicy repeat_mode)
+{
+ GeglSamplerLevel *level = &sampler->level[0];
+ if ((x + level->context_rect.x < level->sampler_rectangle.x)
+ || (y + level->context_rect.y < level->sampler_rectangle.y)
+ || (x + level->context_rect.x + level->context_rect.width
+ > level->sampler_rectangle.x + level->sampler_rectangle.width)
+ || (y + level->context_rect.y + level->context_rect.height
+ > level->sampler_rectangle.y + level->sampler_rectangle.height))
+ {
+ level->sampler_rectangle = _gegl_sampler_compute_rectangle (sampler, x, y, 0);
+
+ gegl_buffer_get (sampler->buffer,
+ &level->sampler_rectangle,
+ 1.0,
+ sampler->interpolate_format,
+ level->sampler_buffer,
+ GEGL_SAMPLER_MAXIMUM_WIDTH * GEGL_SAMPLER_BPP,
+ repeat_mode);
+ }
+
+ {
+ gint dx = x - level->sampler_rectangle.x;
+ gint dy = y - level->sampler_rectangle.y;
+ gint sof = (dx + dy * GEGL_SAMPLER_MAXIMUM_WIDTH) * GEGL_SAMPLER_BPP;
+ guchar *buffer_ptr = (guchar *)level->sampler_buffer;
+
+ return (gfloat*)(buffer_ptr+sof);
+ }
+}
G_END_DECLS
diff --git a/perf/test-rotate.c b/perf/test-rotate.c
index e21923b..628f911 100644
--- a/perf/test-rotate.c
+++ b/perf/test-rotate.c
@@ -9,7 +9,7 @@ main (gint argc,
gegl_init (&argc, &argv);
- buffer = test_buffer (2048, 1024, babl_format ("RGBA float"));
+ buffer = test_buffer (1024, 1024, babl_format ("RGBA float"));
gegl = gegl_node_new ();
source = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", buffer, NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]