gpt4 book ai didi

javascript - 如何优化 60fps 模拟器的 Canvas 性能?

转载 作者:行者123 更新时间:2023-11-30 20:04:23 24 4
gpt4 key购买 nike

我想用 JavaScript 编写一个 gameboy 模拟器。屏幕分辨率为 160 x 144。它有四种颜色:黑色、深灰色、浅灰色和白色。 gameboy 的屏幕刷新率为 60fps。

我有一个 screen 数组,其大小为 160*144=23040,其中每个索引存储 0-3 的颜色阴影。

为了向用户呈现屏幕,我想使用 HTML5 Canvas 。据我了解,最直接的方法是创建一个 ImageData带有 Uint8ClampedArray RGBA 位图的对象,并通过 putImageData 将其传递到 Canvas 。

为此,我必须将屏幕的每一帧转换为 Uint8ClampedArray,并将每个阴影转换为各自的 4 字节 RGBA 数字。这个新的 RGBA 位图的大小为 (160 * 144 * 4 bytes per pixel = 92160:

function screenToBuffer(screen) {
return Uint8ClampedArray.from(screen.map(shade => shadeToRGBA(shade)).flat());
}

然后,这个缓冲区被传递给用户提供的回调函数,他们将在 Canvas 上像这样显示它:

onFrame: function(frameBuffer) {
var image = new ImageData(frameBuffer, 160, 144)
ctx.putImageData(image, 0, 0);
}

这在理论上工作得很好,但这是一种幼稚的方法,而且我发现它根本没有效率。通过使用探查器,仅 screenToBuffer 函数就需要约 25 毫秒。如果屏幕要以 60fps 的速度更新,则需要每 16.6 毫秒渲染一次!

解决这个问题的最佳方法是什么?创建一个全新的 92kb Uint8ClampedArray 并在每帧映射 23,000 种颜色的成本太高了。

我想保留 screen 数组,因为它比 Uint8ClampedArray 更小,而且在我的代码中更容易推理。我认为最好初始化一个 Uint8ClampedArray 一次,并在 screen 数组发生变化时更新它。这样我就可以简单地返回每一帧的 RGBA 缓冲区,它应该已经与我的屏幕同步了。

我还想知道是否每帧创建一个新的 92kb ImageData 对象也是资源密集型的,是否有更好的方法来处理它。

有什么建议吗?

最佳答案

提前捆绑绘制调用并保存调色板,您不应该对此有太多问题。

看看我下面的代码片段:

//Generate output node for time
var output = document.body.appendChild(document.createElement("p"));
//Generate canvas
var canvas = document.body.appendChild(document.createElement("canvas"));
var ctx = canvas.getContext("2d");
canvas.style.width = "500px";
//Setup canvas
canvas.width = 160;
canvas.height = 144;
//Generate color pallette
var colors = ["black", "#444", "#ccc", "white"]
.map(function (b) {
ctx.fillStyle = b;
ctx.fillRect(0, 0, canvas.width, canvas.height);
return ctx.getImageData(0, 0, 1, 1).data;
});
//Generate framedata (referencing back to one of our 4 base colors)
var data = [];
while (data.length < canvas.width * canvas.height) {
data.push(Math.floor(Math.random() * 4));
}
//draw function
function drawCanvas() {
//Start time
var t = Date.now();
//Fill with basic color
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
//Prepare ImageData
var frame = new ImageData(canvas.width, canvas.height);
//Loop through buffer
for (var i = 0; i < data.length; i++) {
var dataPoint = data[i];
//Skip base color
if (dataPoint == 0) {
continue;
}
//Set color from palette
frame.data.set(colors[dataPoint], i * 4);
}
//Put ImageData on canvas
ctx.putImageData(frame, 0, 0);
//Output time
output.textContent = (Date.now() - t).toFixed(2);
//Schedule next frame
requestAnimationFrame(drawCanvas);
}
//Start drawing
drawCanvas();
//Start simulation at 60 fps
setInterval(function () {
data = data.map(function () { return Math.floor(Math.random() * 4); });
}, 16);

我每帧持续约 2 毫秒。

关于javascript - 如何优化 60fps 模拟器的 Canvas 性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53067088/

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