gpt4 book ai didi

Haxe 和 NME : fastest method for per pixel bitmap manipulation

转载 作者:行者123 更新时间:2023-12-04 00:58:58 24 4
gpt4 key购买 nike

这是一个小项目,用于测试 NME 在不同版本(Windows c++、Flash)下的像素级操作性能。

它使用 BitmapData.setPixel 逐个修改像素(每帧 320x240)。 C++ 构建运行在 22 FPS ,而 闪存构建运行在 ~100 FPS 左右。与闪存相比,C++ 构建的性能大幅下降的原因是什么?如何使用 C++ 构建改进代码以获得更高的 FPS?

Mandelbrot.hx

import nme.display.Sprite;
import nme.display.Bitmap;
import nme.display.BitmapData;
import nme.text.TextField;
import nme.events.Event;
import nme.events.TimerEvent;
import nme.utils.Timer;
import nme.geom.Matrix;
import nme.geom.Rectangle;
import nme.utils.ByteArray;

class Mandelbrot
{
public static function main() : Void
{
new Mandelbrot();
}

public var pixels:Array<Array<Int>>;

public var colorModifier:Int;
private var bitmapData:BitmapData;
private var bigBitmapData:BitmapData;

private var fps:TextField;

private var width:Int;
private var height:Int;
private var matrix:Matrix;

public function new()
{
width = 320; //Std.int(flash.Lib.current.stage.stageWidth/2);
height = 240; //Std.int(flash.Lib.current.stage.stageHeight/2);

var scale:Float = 2;//flash.Lib.current.stage.stageWidth/width;
matrix = new Matrix();
matrix.scale(scale, scale);

var setBitmap:Bitmap = new Bitmap();
bitmapData = new BitmapData( width , height , false , 0x000000 );
bigBitmapData = new BitmapData( nme.Lib.current.stage.stageWidth , nme.Lib.current.stage.stageHeight , false , 0x000000 );

setBitmap.bitmapData = bigBitmapData;

nme.Lib.current.addChild( setBitmap );

var maxIterations:Int = 128;

pixels = new Array();


var beforeTime = nme.Lib.getTimer();

var xtemp;
var iteration;
var x0:Float = 0;
var y0:Float = 0;
for(ix in 0...width) {
pixels[ix] = new Array();
for(iy in 0...height) {
x0 = 0;
y0 = 0;
iteration = 128;

while ( x0*x0 + y0*y0 <= 4 && iteration > 0 )
{
xtemp = x0*x0 - y0*y0 + (ix-14*5000)/50000;
y0 = 2*x0*y0 + (iy-(height/0.6))/50000;
x0 = xtemp;

iteration--;
}

pixels[ix][iy] = iteration;
}
}

var afterTime = nme.Lib.getTimer();

var tf = new TextField();
tf.width = 400;
tf.text = "Generating fractal took "+(afterTime-beforeTime)+" ms";
nme.Lib.current.addChild(tf);

fps = new TextField();
fps.width = 400;
fps.y = 10;
fps.text = "FPS: ";
nme.Lib.current.addChild(fps);

colorModifier = 2;
var timer:haxe.Timer = new haxe.Timer(10);

runLoop();
timer.run = runLoop;
}

public function runLoop() {
var r:Int=0, b:Int=0, g:Int=0;
var pixel:Int = 0;

var beforeTime = nme.Lib.getTimer();

for(iy in 0...height) {
for(ix in 0...width) {
pixel = pixels[ix][iy];
r = pixel + colorModifier;
g = pixel + colorModifier + r;
b = pixel + colorModifier + g;
bitmapData.setPixel(ix, iy, (r<<16 | g<<8 | b));
}
}

bigBitmapData.draw(bitmapData, matrix, null, null, null, false);
var afterTime = nme.Lib.getTimer();
fps.text = "FPS: "+Math.round(1000/(afterTime-beforeTime));

colorModifier += 2;
if(colorModifier > 65530)
colorModifier = 0;


}
}

曼德尔布罗特文件

<?xml version="1.0" encoding="utf-8"?>
<project>
<app
file="Mandelbrot.hx"
title="Mandelbrot sample"
package="org.haxe.nme.mandelbrot"
version="1.0.0"
company="nme"
main="Mandelbrot"
/>
<window
width="640"
height="480"
orientation="landscape"
fps="60"
background="0xffffff"
resizeable="true"
hardware="true"
/>
<classpath name="." />
<haxelib name="nme" />
<ndll name="std" />
<ndll name="regexp" />
<ndll name="zlib" />
<ndll name="nme" haxelib="nme" />
<setenv name="SHOW_CONSOLE"/>
</project>

最佳答案

查看 nme.Memory API。这个想法是创建一个具有正确大小的 ByteArray (或从 BitmapData 获取),选择它作为当前虚拟内存空间并直接操作其字节。

使用 Flash,您将获得大约 10 倍的速度提升,并且使用 CPP 目标也应该更快。 不要忘记在 Release 模式下编译 否则方法内联将被禁用并且性能会受到很大影响。

基本用法示例(未经测试的代码):

var rect:Rectangle = bitmapData.rect;

// 32bits integer = 4 bytes
var size:Int = bitmapData.width * bitmapData.height * 4;

// The virtual memory space we'll use
var pixels:ByteArray = new ByteArray();

// CPP does not support setting the length property directly
#if (cpp) pixels.setLength(size);
#else pixels.length = size; #end

// Select the memory space (call it once, not every frame)
Memory.select(pixels);

// And in your loop set your color
// Color is in BGRA mode, nme.Memory can only be used in little endian mode.
Memory.setI32((y * width + x) * 4, color);

// When you're done, render the BitmapData
// (don't forget to reset the ByteArray position)
pixels.position = 0;
bitmapData.setPixels(rect, pixels);

请记住,这是一个非常基本的代码示例。在您的情况下,您需要对其进行调整并实际使用双倍大小的 ByteArray,因为您还需要存储迭代计数。可以在主循环中优化嵌套循环,并且可以避免大量额外的索引/地址计算:

// Note the size * 2 !
// First part of the ByteArray will be used to store the iteration count,
// the second part to draw the pixels.
#if (cpp) pixels.setLength(size * 2);
#else pixels.length = size * 2; #end

Memory.select(pixels);

// First loop storing iteration count
for (iy in 0...height)
{
for (ix in 0...width)
{
// ... do some stuff ...
Memory.setI32((iy * width + ix) << 2, iteration);
}
}

// In your runLoop :
for (i in 0...(height * width))
{
// Get the iteration count
var pixel:Int = Memory.getI32(i << 2);

r = pixel + colorModifier;
g = pixel + colorModifier + r;
b = pixel + colorModifier + g;

// Note that we're writing the pixel in the second part of our ByteArray
Memory.setI32(size + (i << 2), r | g << 8 | b << 16);
}

// Sets the position to the second part of our ByteArray
pixels.position = size;
bitmapData.setPixels(rect, pixels);

就是这样。如果您真的不想在 Flash 目标上使用 Alchemy 操作码,则下一个最快的 blit 像素方法是使用 getVector() 类中的 setVector()/ BitmapData。但它确实没有那么快。

关于Haxe 和 NME : fastest method for per pixel bitmap manipulation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10157787/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com