views:

454

answers:

2

I have a performance question about pixel bender. I want to enlarge many BitmapData (double their size into new BitmapData). I was doing this with as3, but wanted to use pixel bender to get better performance. On my machine, I get better performance out of pixel bender demonstrations then as3.

To my surprise (or bad coding / understanding), I am getting much worse performance out of pixel bender -- 2 seconds vs 1/2 second! I expected to get at least the same performance as as3. What am I doing wrong?

I got the straightforward pixel bender code here (and it is included below for easy reference).

package
{

import flash.display.BitmapData;
import flash.display.Shader;
import flash.display.ShaderJob;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.geom.Matrix;

public class flashFlash extends Sprite
{


[Embed ( source="pixelbender/bilinearresample.pbj", mimeType="application/octet-stream" ) ]
private static var BilinearScaling:Class;

public function flashFlash( ):void
{
    stage.align = StageAlign.TOP_LEFT;
    stage.scaleMode = StageScaleMode.NO_SCALE;

    addEventListener( Event.ENTER_FRAME, efCb, false, 0, true );
}

private function efCb( evt:Event ):void
{
    removeEventListener( Event.ENTER_FRAME, efCb, false );

    traceTime( "init" );

    var srcBmd:BitmapData = new BitmapData( 80, 120, false, 0 );
    var destBmd:BitmapData = new BitmapData( 160, 240, false, 0 );

    var mx:Matrix = new Matrix( );
    mx.scale( 2, 2 );
    for (var i:uint = 0; i < 3000; i++)
    {   destBmd.draw( srcBmd, mx );
    }

    traceTime( "scaled with as3" );

    // create and configure a Shader object
    var shader:Shader = new Shader( );
    shader.byteCode = new BilinearScaling( );
    shader.data.scale.value = [.5];
    shader.data.src.input = srcBmd;

    for (var j:uint = 0; j < 3000; j++)
    {
        var shaderJob:ShaderJob = new ShaderJob( );
        shaderJob.shader = shader;
        shaderJob.target = destBmd;
        shaderJob.start( true );
    }

    traceTime( "scaled with pixel bender bilinearresample.pbj" );
}

private static var _lastTraceTime:Number = new Date().getTime();
public static function traceTime( note:String ):Number
{   var nowTime:Number = new Date().getTime();
    var diff:Number = (nowTime-_lastTraceTime);
    trace( "[t" + diff + "] " + note );
    _lastTraceTime = nowTime;
    return diff;
}

}
}

And the pixel bender code:

<languageVersion : 1.0;>

kernel BilinearResample
<   namespace : "com.brooksandrus.pixelbender";
    vendor : "Brooks Andrus";
    version : 1;
    description : "Resizes an image using bilinear resampling. Constrains aspect ratio - divide Math.max( input.width / output.width, input.height / output.height ) and pass in to the scale parameter";
>
{
    parameter float scale
    <
        minValue: 0.0;
        maxValue: 1000.0;
        defaultValue: 1.0;
    >;

    input image4 src;
    output pixel4 dst;

    void
    evaluatePixel()
    {
        // scale should be Math.max( src.width / output.width, src.height / output.height )
        dst = sampleLinear( src, outCoord() * scale ); // bilinear scaling
    }
}
+1  A: 

I vaguely remember hearing that while the process of connecting to a pixel bender file etc is slower, the processing itself is faster. So I imagine what you'd see is that as image size gets larger, the pixel bender filter may eventually get more efficient. Or maybe PixelBender is best saved for slightly more complex image manipulations.

quoo
+3  A: 

I think the problem is that you are really comparing Pixel Bender against native player code, not against "actionscript". I doubt Pixel Bender will ever win on that scenario.

The scaling that takes place here destBmd.draw( srcBmd, mx ); is coded directly in the player; that's probably as fast as you can get (using an equivalent algorithm). Your kernel on the other hand has at least to be compiled (or JIT compiled) first in order to run (probably there are a number of other reasons for it to be slower; I don't know much about the specifics, though).

Check out this post from the blog of a Flash Player engineer:

A long time ago, back in Flash Player 8 days we had the idea of adding a generic way to do bitmap filters. Hard coding bitmap filters like we did for Flash Player 8 is not only not flexible, but has the burden of adding huge amounts of native code into the player and having to optimize it for each and every platform. The issue for us has always been how you would author such generic filters. Various ideas were floating around but in the end there was one sticking point: we had no language and no compiler. After Macromedia’s merger with Adobe the Flash Player and the Adobe Pixel Bender team came together and we finally had what we needed: a language and a compiler.

So, basically, Pixel Bender is faster than manipulating pixels directly in Actionscript. It will outperform an equivalent zillion of setPixel and getPixel calls. But it won't be faster than the player itself (again, using the same algorithm).

In a way, what you're trying to do is like writting, say, a glow filter in PB. Sure, it's cool and you can learn a lot from it if you're interested in image processing. But if your filter is meant to work just like the native filter, there's not much point in it, aside from educational purposes: the native filter will be faster and it's already available, without an extra line of code.

Juan Pablo Califano