buffer: make bilinear interpolation from mipmap be default for scaled get

gegl_buffer_get's last argument the repeat-mode is now a combined bit-field
flags argument. In addition to choosing the edge repeat behavior for the fetch
we can now also control the interpolation used when scaling from the nearest
bigger mipmap level explicitly by oring one of the buffer scaling modes into
the flags.

The available values that can be | in with the repeat-mode, are, with the
performance scaling factors relative to the default, GEGL_BUFFER_BILINEAR, note
that for the range 0-2.0 the default is boxfilter - since it is a nicer
transition to nearest neighbor.

GEGL_BUFFER_NEAREST     8.0
GEGL_BUFFER_BILINEAR    1.0
GEGL_BUFFER_BOXFILTER   0.4

nearest uses nearest neighbor sampling from the next bigger size, bilinear uses
a bilinear interpolation of the values from the bigger available size, sampling
2x2 pixels for each output pixel, while boxfilter uses a 3x3 neighbourhood -
which is sufficient for accurate box-filtering from the next bigger power of
two scale in a mip-map.

The names for these flags, in particular the prefix, might change, if neither
of them are passed in GEGL_BUFFER_BILINEAR is assumed, this is slightly lower
quality than the previoux default boxfilter, but is 5-6 times faster - while
still being much better than nearest neighbor - and as we are zooming out; the
more correct mipmap scaling dominates.
parent ce12e4f4
......@@ -1889,11 +1889,22 @@ _gegl_buffer_get_unlocked (GeglBuffer *buffer,
const Babl *format,
gpointer dest_buf,
gint rowstride,
GeglAbyssPolicy repeat_mode)
GeglAbyssPolicy flags)
{
gboolean do_nearest = (repeat_mode & GEGL_BUFFER_NEAREST) != 0;
gboolean do_bilinear = (repeat_mode & GEGL_BUFFER_BILINEAR) != 0;
repeat_mode &= 0x7;
GeglAbyssPolicy repeat_mode = flags & 0x7; /* mask off interpolation from repeat mode part of flags */
gint interpolation = (flags & GEGL_BUFFER_BOXFILTER); /* BOXFILTER is and of all interpols */
if (interpolation == 0)
{
/* with no specified interpolation we aim for a trade-off where
100-200% ends up using box-filter - which is a better transition
to nearest neighbor which happens beyond 200% further below.
*/
if (scale > 1.0)
interpolation = GEGL_BUFFER_BOXFILTER;
else
interpolation = GEGL_BUFFER_BILINEAR; /*about 2x as fast as box filter*/
}
if (gegl_cl_is_accelerated ())
{
......@@ -2007,9 +2018,9 @@ _gegl_buffer_get_unlocked (GeglBuffer *buffer,
buf_width = x2 - x1;
buf_height = y2 - y1;
if (!do_nearest && scale <= 1.99)
if ((interpolation != GEGL_BUFFER_NEAREST) && scale <= 1.99)
{
if (do_bilinear)
if (interpolation == GEGL_BUFFER_BILINEAR)
{
buf_width += 1;
buf_height += 1;
......
......@@ -42,8 +42,9 @@ typedef enum {
GEGL_ABYSS_LOOP = 2,
GEGL_ABYSS_BLACK = 3,
GEGL_ABYSS_WHITE = 4,
GEGL_BUFFER_NEAREST = 32,
GEGL_BUFFER_BILINEAR = 64
GEGL_BUFFER_BILINEAR = 16,
GEGL_BUFFER_NEAREST = 32,
GEGL_BUFFER_BOXFILTER = 48,
} GeglAbyssPolicy;
GType gegl_abyss_policy_get_type (void) G_GNUC_CONST;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment