【问题标题】:why is WebGL slower than Canvas 2D in my game?为什么在我的游戏中 WebGL 比 Canvas 2D 慢?
【发布时间】:2014-07-16 22:19:56
【问题描述】:

我在我的游戏中添加了 WebGL 支持,但我有一个奇怪的问题:它的运行速度甚至比在 Canvas 2D 渲染模式下还要慢,我不明白为什么。

我检查了 Firefox PC、Chrome PC 和 Chrome Android,但它们在网络上运行 WebGL 演示并使用数百个精灵顺利,所以我的代码肯定出错了。

Firefox 的分析器说整个游戏只使用了 7% 的资源,渲染部分只占用了 1.2%。这只是游戏的标题屏幕,只有五个精灵要绘制。虽然速度很慢...

更新:Chrome 的分析器说空闲只有 4%,程序是巨大的 93%,渲染 2.6%。
使用 Canvas 2D 时情况大不相同,76% 空闲,16% 程序,2.3% 用于绘图功能。
我的 WebGL 渲染代码肯定有问题。

更新:Android Chrome 的分析器(在 JXD S5110 上)总是说 program is ~39%,drawArrays 是 ~8%,bufferData ~5%,bindTexture 是 3%。其他一切都可以忽略不计。

如果我的一项功能浪费了所有资源,我会知道该怎么做,但这里的瓶颈似乎是“程序”(浏览器本身?)和 webgl 方法,这两件事我无法编辑。

请有人看看我的代码并告诉我我做错了什么。

这是我的着色器

<script id="2d-vertex-shader" type="x-shader/x-vertex">
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    uniform vec2 u_resolution;
    uniform vec2 u_translation;
    uniform vec2 u_rotation;
    varying vec2 v_texCoord;
    void main()
    {
        // Rotate the position
        vec2 rotatedPosition = vec2(
             a_position.x * u_rotation.y + a_position.y * u_rotation.x,
             a_position.y * u_rotation.y - a_position.x * u_rotation.x);

        // Add in the translation.
        vec2 position = rotatedPosition + u_translation;

        // convert the rectangle from pixels to 0.0 to 1.0
        vec2 zeroToOne = a_position / u_resolution;

        // convert from 0->1 to 0->2
        vec2 zeroToTwo = zeroToOne * 2.0;

        // convert from 0->2 to -1->+1 (clipspace)
        vec2 clipSpace = zeroToTwo - 1.0;

        gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

        // pass the texCoord to the fragment shader
        // The GPU will interpolate this value between points
        v_texCoord = a_texCoord;
    }
</script>

<script id="2d-fragment-shader" type="x-shader/x-fragment">
    precision mediump float;

    // our texture
    uniform sampler2D u_image;

    // the texCoords passed in from the vertex shader.
    varying vec2 v_texCoord;

    void main()
    {
         // Look up a color from the texture.
         gl_FragColor = texture2D(u_image, vec2(v_texCoord.s, v_texCoord.t));
    }
</script>

这是我的画布在 WebGL 模式下的创建代码及其上下文。 (我曾经使用多个分层的画布,以避免在每一帧都绘制背景和前景,而它们永远不会改变,这就是为什么画布和上下文都在数组中。)

// Get A WebGL context
liste_canvas[c] = document.createElement("canvas") ;
document.getElementById('game_div').appendChild(liste_canvas[c]);
liste_ctx[c] = liste_canvas[c].getContext('webgl',{premultipliedAlpha:false}) || liste_canvas[c].getContext('experimental-webgl',{premultipliedAlpha:false});
var gl = liste_ctx[c] ;
gl.viewport(0, 0, game.res_w, game.res_h);

// setup a GLSL program
gl.vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
gl.fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
gl.program = createProgram(gl, [gl.vertexShader, gl.fragmentShader]);
gl.useProgram(gl.program);

// look up where the vertex data needs to go.
positionLocation = gl.getAttribLocation(gl.program, "a_position");
texCoordLocation = gl.getAttribLocation(gl.program, "a_texCoord");

// provide texture coordinates for the rectangle.
texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    0.0,  0.0,
    1.0,  0.0,
    0.0,  1.0,
    0.0,  1.0,
    1.0,  0.0,
    1.0,  1.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable( gl.BLEND ) ;

gl.posBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, gl.posBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    0.0,  0.0,
    1.0,  0.0,
    0.0,  1.0,
    0.0,  1.0,
    1.0,  0.0,
    1.0,  1.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

在我的图片的 .onload 函数中,我添加了

var gl = liste_ctx[c] ;

this.texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this );

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

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.bindTexture(gl.TEXTURE_2D, null);

这是我的 draw_sprite() 函数的 WebGL 部分:

var gl = liste_ctx[c] ;

gl.bindTexture(gl.TEXTURE_2D, sprites[d_sprite].texture);

var resolutionLocation = gl.getUniformLocation(gl.program, "u_resolution");
gl.uniform2f(resolutionLocation, liste_canvas[c].width, liste_canvas[c].height);

gl.bindBuffer(gl.ARRAY_BUFFER, gl.posBuffer);

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
     topleft_x , topleft_y ,
     topright_x , topright_y ,
     bottomleft_x , bottomleft_y ,
     bottomleft_x , bottomleft_y ,
     topright_x , topright_y ,
     bottomright_x , bottomright_y ]), gl.STATIC_DRAW);

gl.drawArrays(gl.TRIANGLES, 0, 6);

我做错了什么?

【问题讨论】:

  • game.res_w、game.res_h的值是多少?它们与画布大小有何关系?
  • 这些是游戏的分辨率,宽度为 900,高度为 600。大多数情况下,我的画布都是这个大小,但有些(背景和前景)可能会更大,因为它们会滚动。

标签: webgl


【解决方案1】:

是什么让它这么慢是使用了几个 webgl 画布,我现在只使用一个,它工作得更好。但是它仍然比 Canvas 2D 慢了一点,并且分析器说 65% 是空闲的,而它滞后得要命,所以我真的不明白......

编辑:我想我明白了。由于我的计算机运行的是 WinXP,无法启用 WebGL 的硬件加速,因此浏览器使用软件渲染,这就解释了为什么 Chrome 的分析器中的“程序”很大。但是,硬件加速似乎适用于 2d 上下文,这就是它更快的原因。

【讨论】:

    【解决方案2】:

    这可能会有所帮助:What do the "Not optimized" warnings in the Chrome Profiler mean?

    相关链接:

    1. https://groups.google.com/forum/#!topic/v8-users/_oZ4fUSitRY
    2. https://github.com/petkaantonov/bluebird/wiki/Optimization-killers

    对于“优化太多次”,这意味着函数参数/行为变化太大,因此 Chrome 不得不不断地重新优化它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-06
      • 2015-11-03
      • 1970-01-01
      • 2019-10-31
      • 2012-02-16
      • 1970-01-01
      • 2013-06-25
      相关资源
      最近更新 更多