gdk_pixbuf scaling - variable interplation tables



gdk_pixbuf gurus:

Please cc: me on any response since I'm not on this alias.

I am currently working to make gdk-pixbuf work faster on Solaris.
We are making use of the mediaLib library which is a front-end to
the VIS multimedia acceleration UltraSparc chipset.

I notice that the various scaling functions use variable size
interpolation tables when the interpolation type is PIXOPS_INTERP_TILES,
PIXOPS_INTERP_BILINEAR, or PIXOPS_INTERP_HYPER.  Using PIXOPS_INTERP_HYPER
as an example, it calls bilinear_make_weights.  In this function the
table size is calculated by the following lines

  int n_x = ceil(1/x_scale + 2.0);
  int n_y = ceil(1/y_scale + 2.0);

So, when scaling down, the table gets larger.  It obviously makes sense
for the interpolation tables to get larger when the scaling factors get
smaller.  This makes sure that all source pixels contribute to the
resulting image when the scaling factor is <= 1.

The mediaLib functions also support the ability to use variable sized
interpolation tables.  However, there is a difference.  The mediaLib
functions use 2 1-dimentional tables where the gdk_pixbuf functions
use a single 2-dimensional table.

In tile_make_weights and bilinear_make_fast_weights, the 2-dimensional
tables used by gdk_pixbuf are simply two 1-dimensional tables multiplied
together and are trivial to separate for use with mediaLib.

However, things are not so easy for bilinear_make_weights used by
PIXOPS_INTERP_HYPER.  This function seems a bit of a puzzle to me.

It contains the following for loop:

--code example start--

  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
      {
        int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset)
 * n_x * n_y;
        double x = (double)j_offset / SUBSAMPLE;
        double y = (double)i_offset / SUBSAMPLE;
        int i,j;
        int total = 0;

        for (i = 0; i < n_y; i++)
          for (j = 0; j < n_x; j++)
            {
              double w;
              int weight;

              w = bilinear_quadrant  (0.5 + j - (x + 1 / x_scale), 0.5 + j - x,
0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
              w += bilinear_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j,
0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
              w += bilinear_quadrant (0.5 + j - (x + 1 / x_scale), 0.5 + j - x,
1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
              w += bilinear_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j,
1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
              weight = 65536 * w * x_scale * y_scale * overall_alpha + 0.5;
              *(pixel_weights + n_x * i + j) = weight;
              total += weight;
            }

        correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
      }


--code example end--

It might not be possible to make 2 1-d tables that exactly correspond to
the table as built above.  The correct_total function is confusing to
me, and the fact that i/j/x/y are all used to compute the value "w"
(which in turn is used to compute weight and then  pixel_weights)
makes me suspect that this interpolation table is not simply two 1-d
tables multiplied together. 

If I'm wrong in that assumption, and it really can be broken down into
two 1-d tables, I'd appreciate it if anyone could clarify what I am 
missing.  Otherwise, I would appreciate it if someone could explain to me
exactly what the interpolation table is trying to accomplish and whether
a reasonable approximation can be accomplished via two 1-d tables.

Lastly, I suppose it might be possible that this function is generating
a more complicated interpolation table than is really needed.  If it is
possible to replace this table with a simpler table that is similarly 
effective, uses less processing time, and fits better with the
two 1-d table approach required by mediaLib, then everyone gains.

I suggest this last idea because it obviously saves time to use two
1-d tables rather than building a 2-d table.  If gdk moved to this 
model as well, then it would not be necessary to spend time building
the full 2-d table.  pixops_process could just multiply the two 1-d
tables together when it has calculate "run_weights" anyway.

I would be happy to do the work to make pixops.c use 1-d tables 
that are multiplied together rather than building the current 2-d
tables, if someone can help me unravel bilinear_make_weights (or
help me to come up with a reasonable approximation that fits in 
the 2 1-d table approach).

Thanks!

Brian




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]