Hi everyone,<div><br></div><div>I&#39;m using cairo and pixman to composite images.</div><div>I tested image scaling performance with bilinear filtering.</div><div>But it&#39;s a little bit slower than I expected.</div><div>
<br></div><div>Test was performed with cairo 1.8.8 &amp; pixman 0.21.2 on ubuntu 10.04 with intel quad core CPU @2.66GHz.</div><div>I used cairo image surface for both source and destination.</div><div><br></div><div><br>
</div><div>Test codes are something like this...</div><div><br></div><div>#define SCALE_X 2.0</div><div>#define SCALE_Y 2.0</div><div><br></div><div><div>cairo_scale(cr, SCALE_X, SCALE_Y);</div><div>cairo_set_source_surface(cr, srcSurface, 0, 0);</div>
<div>cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BILINEAR);</div><div>cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);</div><div><br></div><div>startTime = rdtsc();</div><div>cairo_paint(ctx);</div><div>endTime = rdtsc();</div>
</div><div><br></div><div><br></div><div>What I understand about image scaling procedure is as follows</div><div><br></div><div>1. Allocate(or acquire statically allocated buffer) horizontal source scanline buffer to store interpolated pixels.</div>
<div>2. Fetch a scanline from source image to source scanline buffer with bilinear interpolation.</div><div>3. Composite source scanline and destination scanline with operator SRC.</div><div>4. Go to next scanline.</div><div>
5. Free(or release) source scanline buffer.</div><div><br></div><div><br></div><div>My optimization point is</div><div><br></div><div>1. It seems possible to avoid fetching by directly combining bilinear interpolated result with destination.</div>
<div>2. Bilinear interpolation can be optimized using double-blend trick with a little bit of precision loss.</div><div><br></div><div>Optimization 1 can reduce one memory write and one memory read operation.</div><div>I think it will not affect the performance significantly.</div>
<div>However, it can be helpful on some machines with limited cache.</div><div><br></div><div>Optimization 2 is more critical for image scaling with bilinear filtering.</div><div>I wrote some codes for bilinear_interpolation@pixman-bits-image.c</div>
<div><br></div><div>// Optimization 2</div><div><div>static force_inline uint32_t bilinear_interpolation (uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br, int distx, int disty)</div></div><div>{</div><div><div>    <meta http-equiv="content-type" content="text/html; charset=utf-8">int distxy, distxiy, distixy, distixiy;</div>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    uint32_t rb, ga;</div><div><br></div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    distxy = distx * disty;</div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>
    distxiy = (disty &lt;&lt; 8) - <meta http-equiv="content-type" content="text/html; charset=utf-8">distxy;</div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    distixy = (distx &lt;&lt; 8) - <meta http-equiv="content-type" content="text/html; charset=utf-8">distxy;</div>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    distixiy = 256*256 - (disty &lt;&lt; 8) - (distx &lt;&lt; 8) + <meta http-equiv="content-type" content="text/html; charset=utf-8">distxy;</div><div>
<br></div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    <meta http-equiv="content-type" content="text/html; charset=utf-8">distxy = <meta http-equiv="content-type" content="text/html; charset=utf-8">distxy &gt;&gt; 8;</div>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    <meta http-equiv="content-type" content="text/html; charset=utf-8">distxiy = <meta http-equiv="content-type" content="text/html; charset=utf-8">distxiy &gt;&gt; 8;</div>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    <meta http-equiv="content-type" content="text/html; charset=utf-8">distixy = <meta http-equiv="content-type" content="text/html; charset=utf-8">distixy &gt;&gt; 8;</div>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    <meta http-equiv="content-type" content="text/html; charset=utf-8">distixiy = <meta http-equiv="content-type" content="text/html; charset=utf-8">distixiy &gt;&gt; 8;</div>
<div><br></div><div>    /* Red and Blue */</div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    rb = (0x00FF00FF &amp; tl)*<meta http-equiv="content-type" content="text/html; charset=utf-8">distixiy + (0x00FF00FF &amp; tr)*<meta http-equiv="content-type" content="text/html; charset=utf-8">distixy + (0x00FF00FF &amp; bl)*<meta http-equiv="content-type" content="text/html; charset=utf-8">distxiy + (0x00FF00FF &amp; br)*<meta http-equiv="content-type" content="text/html; charset=utf-8">distxy;</div>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    rb = (rb &gt;&gt; 8) &amp; 0x00FF00FF;</div><div><br></div><div>    /* Green and Alpha */</div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>
    ga = (0x00FF00FF &amp; (tl &gt;&gt; 8))*<meta http-equiv="content-type" content="text/html; charset=utf-8">distixiy + (0x00FF00FF &amp; (tr &gt;&gt; 8))*<meta http-equiv="content-type" content="text/html; charset=utf-8">distixy + (0x00FF00FF &amp; (bl &gt;&gt; 8))*<meta http-equiv="content-type" content="text/html; charset=utf-8">distxiy + (0x00FF00FF &amp; (br &gt;&gt; 8))*<meta http-equiv="content-type" content="text/html; charset=utf-8">distxy;</div>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    ga = ga &amp; 0xFF00FF00;</div><div><br></div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>    return rb | ga;</div></div>
<div>}</div><div><br></div><div>Optimization 2 increased the performance by more than twice.</div><div>But it does not always produce the same result as the original code, which is also an approximation of bilinear interpolation.</div>
<div>So it can cause pixel correctness issues on some test cases.</div><div>I&#39;ve done some numerical analysis and it appears that at most you would have a difference of 1 for each RGBA value as the original code. </div>
<div><br></div><div>Let me know if you need for information / explanation. </div><div><br></div><div>It&#39;s my great pleasure if this can be useful for your project.</div><div>Thank you.</div>