使用原始数据的WebGL比js Image()慢

时间:2015-07-01 17:10:14

标签: javascript html5 opengl-es webgl

我们正在编写一个用于流视频的Web客户端,一种类型的流使用专有库,因此我们无法使用支持标准网址的当前插件或HTML标记。 我有几年的OpenGL经验,所以我决定试用WebGL来渲染原始数据帧。

使用js Image()加载png文件非常快。但使用原始RGBA数据进行渲染非常慢。

我将原始数据放在Uint8Array()中并使用接受宽度高度的gl.texImage2D(),而PNG渲染使用接受图像且没有宽度高度的gl.texImage2D()版本。

我会假设原始数据会更快,因为它不必加载和解码png文件,但它似乎是倒退。

我的背景主要是C ++,并且对桌面OpenGL有相当多的经验。 HTML5和javascript对我来说还是一个新手。

为什么WebGL渲染Image()(1024x1024)要快得多,甚至原始数据(32x32)的小图像要慢得多?有没有办法加快速度?我在最新版本的Firefox上运行它。

编辑: 问题实际上是将数据从插件传递给javascript。我正在使用Date.getTime()进行分析,但显然这不是一个好方法,因为创建数组之前和之后的时间和从插件获取数据是相同的。我已经切换到从本地HTTP服务器获取数据,这在获取和呈现原始数据时表现出了很大的性能提升。

2 个答案:

答案 0 :(得分:3)

嗯,让我们进行测试



var canvas = document.getElementById("c");
var gl = canvas.getContext("webgl");
var work = document.getElementById("w");
var fps = document.getElementById("f");

var imageData = new Uint8Array(canvas.width * canvas.height * 4);

var program = webglUtils.createProgramFromScripts(
    gl, ["vshader", "fshader"], ["a_position"]);
gl.useProgram(program);

var verts = [
      1,  1,  
     -1,  1,  
     -1, -1,  
      1,  1,  
     -1, -1,  
      1, -1,  
];
var vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);

var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

var adjust = 1;
var workAmount = adjust;
var oneFrame = 1 / 50;  // shoot for 50fps since timing is poor
var then = Date.now() * 0.001;
var frameCount = 0;
var maxIndex = canvas.width * canvas.height;

function doStuff() {
    var now = Date.now() * 0.001;
    var deltaTime = now - then;
    then = now;
    ++frameCount;
    
    if (deltaTime < oneFrame) {
        workAmount += adjust;
    } else {
        workAmount = Math.max(workAmount - adjust, adjust);
    }
    
    fps.innerHTML = (1 / deltaTime).toFixed(1);
    work.innerHTML = workAmount;
    
    var color = (frameCount & 1) ? 255 : 128;
    for (var i = 0; i < workAmount; ++i) {
        var index = (Math.random() * maxIndex | 0) * 4;
        imageData[index + 0] = color;
        imageData[index + 1] = color;
        imageData[index + 2] = color;
        imageData[index + 3] = 255;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, 
                     gl.RGBA, gl.UNSIGNED_BYTE, imageData);    
    }
    
    gl.drawArrays(gl.TRIANGLES, 0, 6);

    requestAnimationFrame(doStuff);
}
doStuff();
&#13;
body, document {
    font-family: monospace;
}
#c {
    width: 128px;
    height: 128px;
    border: 1px solid red;
}
#outer {
  position: relative;   
}
#info {
  position: absolute;
  left: 10px;
  top: 10px;
  background-color: white;
  padding: 0.5em;
}
&#13;
<div id="outer">
    <canvas id="c" width="1024" height="1024"></canvas>
    <div id="info">
      <div>fps : <span id="f"></span></div>
      <div>work: <span id="w"></span></div>
    </div>
</div>

<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script id="vshader" type="whatever">
    attribute vec4 a_position;
    varying vec2 v_texcoord;

    void main() {
      gl_Position = a_position;
      v_texcoord = a_position.xy * 0.5 + 0.5;
    }    
</script>
<script id="fshader" type="whatever">
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_sampler;
void main() {
    gl_FragColor = texture2D(u_sampler, v_texcoord);
}
</script>
&#13;
&#13;
&#13;

在我的2014 MBP上,我得到大约20个1024x1024 RGBA / UNSIGNED_BYTE在Chrome上以50fps上传一帧,在Firefox上大致相同

你得到了什么?你确定你的瓶颈是纹理上传而不是其他东西吗?

答案 1 :(得分:0)

缓慢可能来自(至少)3件事:

  1. WebGL必须使用texImage2D进行错误检查。也许浏览器知道Image中的数据始终有效,因此跳过此检查。

  2. WebGL可能需要在幕后进行数据转换;例如,如果您使用预乘alpha;那么WebGL可能需要用原始数据进行转换;而Image元素已经是预乘alpha(最有可能)。

  3. 浏览器在创建TypeArrays时仍然非常缓慢。如果您每帧都在创建一个新的TypeArray,这会降低性能。