前一陣子為了寫整合3D與Dynamic Sound相關套件的Flash程式,但是發覺只要加入的音頻越多的話,
常常會爆出破音甚至在IE上執行時會當掉,想說可能是
Away3D吃掉太多資源所致,
也試著以
Away3DLite改寫後情況也沒好到哪裡,最近剛好找到這篇文章
Using Pixel Bender to calculate information提到因為Flash是單一執行緒程式,當處理大量吃重的運算常效能不彰,
可利用Pixel Bender的多工處理的特性將某些吃重的運算挪到PBJ上面執行
於是參考這幾篇文章發表的程式碼後
Audio mixing with Pixel BenderUsing Pixel Bender with Flash Builder 4 beta as a number crunching engine牛刀小試的改寫成了以下的程式碼
這是PBK程式碼,可多工平行運算用來加總兩個陣列的每個Item的值
<languageVersion : 1.0;>
kernel SumCalculator
<
namespace : "PixelBender";
vendor : "Charlie";
version : 1;
description : "SumCalculator";
>
{
input image1 src;
input image1 src2;
output pixel3 result;
void evaluatePixel()
{
float x = pixel1( sample(src, outCoord()) );
float y = pixel1( sample(src2, outCoord()) );
float z = x+y;
result = pixel3( z, 0.0, 0.0);
}
}
這是AS3程式碼
package
{
import com.bit101.components.*;
import flash.display.*;
import flash.events.*;
import flash.utils.*;
public class FastSumManyArray extends Sprite
{
[Embed(source="./pbks/SumCalculator.pbj", mimeType="application/octet-stream")]
private var KernelClass:Class;
const arraylength:int=5000;
private var array1:Array=new Array(arraylength);
private var array2:Array=new Array(arraylength);
private var array_result:Array=new Array();
private var text3:Text;
private var result:ByteArray;
public function FastSumManyArray()
{
stage.align="TL"
initArray(array1);
initArray(array2);
var text1:Text=new Text(this,0,0,array1.toString());
text1.height=16;
text1.width=1000;
addChild(text1);
var text2:Text=new Text(this,0,30,array2.toString());
text2.height=16;
text2.width=1000;
addChild(text2);
text3=new Text(this,0,60);
text3.height=16;
text3.width=1000;
addChild(text3);
addChild(new PushButton(this,0,100,"Start",clickHandler));
}
private function initArray(array:Array)
{
for(var i=0;i<array.length;i++)
{
array[i]=Math.random();
}
}
private function clickHandler(event:MouseEvent):void
{
initializeHandler(array1,array2);
}
protected function initializeHandler(list:Array, list2:Array):void
{
var byteArray:ByteArray = new ByteArray();
var byteArray2:ByteArray = new ByteArray();
var shader:Shader = new Shader(new KernelClass());
var shaderJob:ShaderJob;
var height:int;
var width:int;
byteArray = convertListToByteArray( list );
byteArray2 = convertListToByteArray( list2 );
width = byteArray.length >> 2;
height = 1;
shader.data.src.width = width;
shader.data.src.height = height;
shader.data.src.input = byteArray;
shader.data.src2.width = width;
shader.data.src2.height = height;
shader.data.src2.input = byteArray2;
result = new ByteArray();
result.endian = Endian.LITTLE_ENDIAN;
shaderJob = new ShaderJob(shader, result, width, height);
shaderJob.addEventListener(Event.COMPLETE, onComplete);
shaderJob.start();
}
protected function onComplete(event:Event):void
{
var length:int = result.length;
var num:Number;
var i:int;
result.position = 0;
for(i = 0; i < length; i += 4)
{
num = result.readFloat();
if(i % 3 == 0)
array_result.push(num);
}
text3.text=array_result.toString();
}
private static function convertListToByteArray(list:Array):ByteArray
{
var retVal:ByteArray = new ByteArray();
var number:Number;
var len:int = list.length;
var i:int;
retVal.endian = Endian.LITTLE_ENDIAN;
for (i; i<len; i++)
{
retVal.writeFloat( Number(list[i]) );
}
retVal.position = 0;
return retVal;
}
}
}
也可利用工具將PBJ反組譯成Assembly language,看看是否有改進的空間,再以
HaXe重新組譯,
壓榨出最大的效能!!!
version : 1
name : 'SumCalculator'
meta namespace : 'PixelBender'
meta vendor : 'Charlie'
meta version : 1
meta description : 'SumCalculator'
param in f0.rg float2 _OutCoord
text0 1-channels src
text1 1-channels src2
param out f1.rgb float3 result
code :
sampleLinear f0.a, text0[f0.rg]
mov f0.b, f0.a
mov f0.a, f0.b
sampleLinear f1.a, text1[f0.rg]
mov f0.b, f1.a
mov f1.a, f0.b
mov f0.b, f0.a
add f0.b, f1.a
mov f2.r, f0.b
mov f2.g, f2.r
loadfloat f0.b, 0
mov f2.b, f0.b
loadfloat f0.b, 0
mov f2.a, f0.b
mov f1.rgb, f2.gba
這是執行結果的畫面
Demo