【问题标题】:What is the best way, to draw a part of an arraybuffer to the canvas?将数组缓冲区的一部分绘制到画布上的最佳方法是什么?
【发布时间】:2014-03-02 22:50:37
【问题描述】:

我有一个ArrayBuffer,还有一个名为module.repaint 的函数,它与ArrayBuffer 一起工作。在每次重绘调用中,我想将 ArrayBuffer 中的颜色放到画布上。

我是这样做的:

imgData.data.set(new Uint8ClampedArray(MEM, 0, siz));

但是是否有可能更快地将 ArrayBuffer 的一部分复制到另一个? 代码:

var MEM = new ArrayBuffer(2*1024*1024);
var canvas, ctx, imgData, siz;

var repaint = function() {
    // module.repaint works on the arraybuffer
    module.repaint();

    imgData.data.set(new Uint8ClampedArray(MEM, 0, siz));
    ctx.putImageData(imgData, 0, 0);

    requestAnimationFrame(repaint);
};

var init = function() {
    canvas = document.getElementById('canvas');
    ctx = canvas.getContext('2d');

    siz = canvas.width*canvas.height*4;

    imgData=ctx.createImageData(canvas.width,canvas.height);

    repaint();
};

【问题讨论】:

    标签: javascript html canvas asm.js


    【解决方案1】:

    请注意,我没有检查增益是否重要,但我可以在这里看到一些有用的优化。

    首先,Uint8ClampedArray 是缓冲区的视图,而不是缓冲区本身,因此您不需要每次都创建它。 (你也可以在一个缓冲区上有多个视图)

    您还应该避免使用imgData.dataset 方法,因为它将所有数据从一个数组复制到另一个数组(这是无用的)。相反,您可以在构造函数上设置Uint8ClampedArray

    使用该代码,MEM 上的每次更改都会自动影响imgData,因为imgData.data 直接指向MEM

    var MEM = new ArrayBuffer(2*1024*1024);
    var canvas, ctx, imgData, siz;
    
    var repaint = function() {
        // module.repaint works on the arraybuffer
        module.repaint();
    
        ctx.putImageData(imgData, 0, 0);
    
        requestAnimationFrame(repaint);
    };
    
    var init = function() {
        canvas = document.getElementById('canvas');
        ctx = canvas.getContext('2d');
    
        siz = canvas.width*canvas.height*4;
    
        imgData = ctx.createImageData(new Uint8ClampedArray(MEM, 0, siz), canvas.width, canvas.height);
    
        repaint();
    };
    

    【讨论】:

      【解决方案2】:

      如果可能,重构你的 module.repaint() 以使用屏幕外画布而不是像素数组。

      这样您就可以将屏幕外画布 drawImage 绘制到屏幕画布上——效率很高,因为 GPU 可以执行 blitting 而不是 CPU 负担。

      putImageData 速度较慢,因为它涉及 CPU 从像素数组中获取数据,在临时数组中设置该数据并将临时数组传输到屏幕上的 imageData。这些都是对 CPU 造成负担并降低性能的活动。

      【讨论】:

      • 该模块是一个asmjs模块。堆对象的 byteLength 必须是 4096 的倍数,堆对象的 byteLength 必须是 2 的幂。
      • markE :你是对的,drawImage 与 putImageData 的速度增益是巨大的,很可能超过使用 asmjs 所能提供的速度。 @IterAtor:阅读markE的答案怎么样?
      • 但是如果我想使用drawImage 方法,那么我必须在每个循环中将实际的 ImageData 转换为图像。我不知道如何从 ArrayBuffer 读取字节,并将像素快速写入画布。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-04
      • 1970-01-01
      • 2017-10-04
      • 2012-11-07
      • 1970-01-01
      • 2018-08-20
      • 1970-01-01
      相关资源
      最近更新 更多