垃圾收集器破坏WebGL页面性能

时间:2016-03-10 13:24:29

标签: javascript performance garbage-collection webgl

enter image description here enter image description here

作为一名webGL开发人员,这些图表让我心碎。不可能 如果垃圾收集器在主线程中运行阻止动画的工作流程超过半秒,则平滑动画可以不间断地播放

我已经尝试了所有这些,缓存,对象池,声明全局变量并使我的返回函数像状态机一样工作,直到我终于发现即使empty call to RequestAnimationFrame itself每秒也会产生高达1mb的垃圾

对RAF的Ping-pong呼叫不会改变我的系统上的垃圾创建率

假设在GC启动时没有可能拥有一个完全响应的webgl页面,我想知道是否有任何替代我们通常在webgl项目中看到的通常代码结构。起初我想使用webWorker并将主线程释放到GC而不中断动画渲染,但代价是钻研OffscreenCanvas界面,但看起来it's only supported in Firefox atm

使用setTimeout仍然会产生抖动,并且被认为是不好的做法,所以我想知道是否真的有一种解决方法可以避免GC中断

1 个答案:

答案 0 :(得分:3)

enter image description here

看起来你的测试页面正在做一些它不应该做的事情。

  • 解析HTML

为什么每帧都在解析HTML?只有在someElement.innerHTML = "..."发生HTML更改时才会发生这种情况。

如果你要更新一个值,比如说FPS,试试这个

<div class="fps">FPS:<span id="fps"></span></div>

然后将div设为固定宽度,以便它不会根据fps改变大小

.fps { width: 100px }

然后为fps值

创建一个文本节点
var fpsNode = document.createTextNode("");
var fpsSpan = document.getElementById("fps");
fpsSpan.appendChild(fpsNode);

现在你可以像这样更新fps了

fpsSpan.nodeValue = someFPSNumber;

我的伏都教。我实际上并没有对它进行分析,但理论上这样做就意味着不需要进行HTML解析,因为每帧都没有新的HTML。最重要的是因为宽度是固定的,所以没有布局要做。

此外,你应该考虑在它自己的堆叠环境中加入类似的东西

.fps { position: absolute; z-index: 2 }

这样浏览器就可以将该元素放入其自己的纹理中,因此不必在同一堆叠上下文中使用其他元素重新渲染。

检查空白的rAF

&#13;
&#13;
function nothing() {
  requestAnimationFrame(nothing);
}
nothing();
&#13;
&#13;
&#13;

我每1.5秒看一次1ms次要GC。你每帧有16毫秒,所以拿1来换GC不会毁了你的一天。

enter image description here

让我们在上面添加我的建议和一些WebGL

&#13;
&#13;
"use strict";
var countNode = document.createTextNode("");
var countElem = document.getElementById("count");
countElem.appendChild(countNode);

twgl.setDefaults({attribPrefix: "a_"});
var m4 = twgl.m4;
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);

var bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 2);

var tex = twgl.createTexture(gl, {
  min: gl.NEAREST,
  mag: gl.NEAREST,
  src: [
    255, 255, 255, 255,
    192, 192, 192, 255,
    192, 192, 192, 255,
    255, 255, 255, 255,
  ],
});

var camera = m4.identity();
var view = m4.identity();
var projection = m4.identity();
var viewProjection = m4.identity();
var world = m4.identity();
var worldInverseTranspose = m4.identity();
var worldViewProjection = m4.identity();
    
var uniforms = {
  u_lightWorldPos: new Float32Array([1, 8, -10]),
  u_lightColor: new Float32Array([1, 0.8, 0.8, 1]),
  u_ambient: new Float32Array([0, 0, 0, 1]),
  u_specular: new Float32Array([1, 1, 1, 1]),
  u_shininess: 50,
  u_specularFactor: 1,
  u_diffuse: tex,
  u_viewInverse: camera,
  u_world: world,
  u_worldInverseTranspose: worldInverseTranspose,
  u_worldViewProjection: worldViewProjection,
  
};
                             
var eye = [1, 4, -6];
var target = [0, 0, 0];
var up = [0, 1, 0];
var count = 0;                            

function render(time) {
  ++count;
  countNode.nodeValue = count;

  time *= 0.001;
  twgl.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

  gl.enable(gl.DEPTH_TEST);
  gl.enable(gl.CULL_FACE);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  m4.perspective(30 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.5, 10, projection);

  m4.lookAt(eye, target, up, camera);
  m4.inverse(camera, view);
  m4.multiply(view, projection, viewProjection);
  m4.rotationY(time, world);

  m4.inverse(world, worldInverseTranspose);
  m4.transpose(worldInverseTranspose, worldInverseTranspose);
  
  m4.multiply(world, viewProjection, worldViewProjection);

  gl.useProgram(programInfo.program);
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  twgl.setUniforms(programInfo, uniforms);
  gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0);

  requestAnimationFrame(render);
}
requestAnimationFrame(render);
&#13;
html, body, canvas {
  margin: 0;
  width: 100%;
  height: 100%;
}
.count {
  width: 100px;
  position: absolute;
  left: 1em;
  top: 1em;
  background-color: rgba(0,0,0,0.8);
  z-index: 2;
  padding: 1em;
  color: white;
}
&#13;
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
   <script id="vs" type="notjs">
uniform mat4 u_worldViewProjection;
uniform vec3 u_lightWorldPos;
uniform mat4 u_world;
uniform mat4 u_viewInverse;
uniform mat4 u_worldInverseTranspose;

attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec2 a_texcoord;

varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

void main() {
  v_texCoord = a_texcoord;
  v_position = (u_worldViewProjection * a_position);
  v_normal = (u_worldInverseTranspose * vec4(a_normal, 0)).xyz;
  v_surfaceToLight = u_lightWorldPos - (u_world * a_position).xyz;
  v_surfaceToView = (u_viewInverse[3] - (u_world * a_position)).xyz;
  gl_Position = v_position;
}
  </script>
  <script id="fs" type="notjs">
precision mediump float;

varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

uniform vec4 u_lightColor;
uniform vec4 u_ambient;
uniform sampler2D u_diffuse;
uniform vec4 u_specular;
uniform float u_shininess;
uniform float u_specularFactor;

vec4 lit(float l ,float h, float m) {
  return vec4(1.0,
              max(l, 0.0),
              (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
              1.0);
}

void main() {
  vec4 diffuseColor = texture2D(u_diffuse, v_texCoord);
  vec3 a_normal = normalize(v_normal);
  vec3 surfaceToLight = normalize(v_surfaceToLight);
  vec3 surfaceToView = normalize(v_surfaceToView);
  vec3 halfVector = normalize(surfaceToLight + surfaceToView);
  vec4 litR = lit(dot(a_normal, surfaceToLight),
                    dot(a_normal, halfVector), u_shininess);
  vec4 outColor = vec4((
  u_lightColor * (diffuseColor * litR.y + diffuseColor * u_ambient +
                u_specular * litR.z * u_specularFactor)).rgb,
      diffuseColor.a);
  gl_FragColor = outColor;
}
</script>
<canvas id="c"></canvas>
<div class="count">
  count: <span id="count"></span>
</div>
&#13;
&#13;
&#13;

仍然没有发现任何事情导致我的帧率下降

enter image description here