gpt4 book ai didi

javascript - 为什么我的 WebGl 帧率在 Chrome 中缓慢下降?

转载 作者:行者123 更新时间:2023-11-30 12:42:28 27 4
gpt4 key购买 nike

在我的 WebGl 程序中,帧率开始很高,然后慢慢下降,内存使用量随着时间的推移而增加。帧率不会无限下降,但会在某个时刻保持一致。这个问题在 IE 和 FF 中可以忽略不计,但在 Chrome 中我的帧率从 30 下降到 10。

我缩小了问题范围:它是由创建正在绘制的数据的函数引起的(在原始程序中)。出于测试目的,我创建了一个将测试数据写入全局变量的函数。测试数据没有以任何方式使用。 fps 下降仍然发生。

var testData;

function createTestData() {
testData = [];
for (var i = 0; i < 5000; i++) {
testData[i] = [];
for (var j = 0; j < 1000; j++) {
testData[i][j] = 1;
}
}
}

如果我注释掉对该函数的一次调用,一切都会按预期进行,帧率不会下降。

在运行时调用 createTestData() 会导致 fps 像开始时一样上升,然后再次缓慢下降。

我的程序进程的 Chrome 内存使用量不到 200mb,离 Chrome 应该有问题的地方还差得很远。

我使用的是 Win 7 和 8、Chrome 35 和 36 以及多个电脑设置。

感觉像是 Chrome 的错误,但我找不到其他人有这个问题,所以这可能是我这边的一些愚蠢的错误。

高度简化版本的完整代码:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<title>WebGl Framedrop Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<script type="text/javascript" src="sylvester.js"></script>
<script type="text/javascript" src="glpsutilskap8.js"></script>
<script type="text/javascript" src="JS_Main.js"></script>

<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
uniform mat4 mvpMatrix;

void main(void)
{
gl_Position = mvpMatrix * vec4(aVertexPosition, 1.0);
}
</script>

<script id="shader-fs" type="x-shader/x-fragment">
void main(void)
{
}
</script>

<style type="text/css">
body {
margin-left: 0px;
margin-top: 0px;
}

canvas {
margin-left: 0px;
margin-top: 0px;
}

</style>
</head>
<body onload="Main()">
<table>
<td style="vertical-align: top;">
<canvas id="WebGL-canvas" style="border: none;" width="800" height="600" ></canvas>
<input type="button" style="margin-left:5px;" value="call createTestData() again" onclick="createTestData()" />
<p>current fps:</p>
<p id="fpsDisplay" style="color:red">default</p>

<p>fps last min:</p>
<p id="fpsMinuteDisplay" style="color:red">default</p>
</table>
</body>
</html>

JS_Main.js

var testData;

function createTestData() {
testData = [];
for (var i = 0; i < 5000; i++) {
testData[i] = [];
for (var j = 0; j < 1000; j++) {
testData[i][j] = 1;
}
}
}

var fZnear = 0.1;
var fZfar = 3000;
var g_fOpenViewAngle = 45;

var gl;
var shaderProgram;

var mMatrix;
var vMatrix;
var pMatrix;
var mvMatrix;
var mvpMatrix;

var requestAnimationFrame = window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame
|| window.oRequestAnimationFrame
;

var wall = {};
wall.vertices = new Array();
wall.triangles = new Array();

var g_nCanvasWidth = 800;
var g_nCanvasHeight = 600;

var fpsCounter;

function Main() {
initGL();
initShaders();
gl.clearColor(0.5, 0.75, 1.0, 1.0);
initBuffers();

createTestData();

fpsCounter = new FpsCounter();
setInterval(setIntervalLoop, 0);
}

function drawScene() {
fpsCounter.update();
document.getElementById('fpsDisplay').innerHTML = fpsCounter.getCountPerSecond();
document.getElementById('fpsMinuteDisplay').innerHTML = fpsCounter.getCountPerMinute();

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

pMatrix = createPerspectiveMatrix(g_fOpenViewAngle, g_nCanvasWidth / g_nCanvasHeight, fZnear, fZfar);
vMatrix = translationMatrix(-100, -100, -100);

drawWall();
}

function drawWall() {
gl.bindBuffer(gl.ARRAY_BUFFER, wall.vertexPositionBufferID);
gl.vertexAttribPointer(vertexPositionAttribute, wall.vertexPositionBufferID.itemSize, gl.FLOAT, false, 0, 0);

for (var i = 0; i < 1000; i++) {
mMatrix = translationMatrix(Math.random() * 200, Math.random() * 200, Math.random() * 200).x(Matrix.I(4));
mvMatrix = vMatrix.x(mMatrix);
mvpMatrix = pMatrix.x(mvMatrix);

setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, wall.vertexPositionBufferID.numItems);
}
}

function translationMatrix(x, y, z) {
var ret = Matrix.I(4);

ret.elements[0][3] = x;
ret.elements[1][3] = y;
ret.elements[2][3] = z;

return ret;
}
;

function setIntervalLoop() {
drawScene();
}

function initBuffers() {
wall.vertexPositionBufferID = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, wall.vertexPositionBufferID);

wall.vertices[0] = Vector.create([1.0, -0.25, 1.0]);
wall.vertices[1] = Vector.create([-1.0, -0.25, 1.0]);
wall.vertices[2] = Vector.create([-1.0, 0.25, 1.0]);
wall.vertices[3] = Vector.create([1.0, 0.25, 1.0]);

wall.vertices[4] = Vector.create([1.0, -0.25, -1.0]);
wall.vertices[5] = Vector.create([-1.0, -0.25, -1.0]);
wall.vertices[6] = Vector.create([-1.0, 0.25, -1.0]);
wall.vertices[7] = Vector.create([1.0, 0.25, -1.0]);

wall.triangles[0] = new IndexedVertexTriangle(wall.vertices, 4, 0, 1);
wall.triangles[1] = new IndexedVertexTriangle(wall.vertices, 4, 1, 5);
wall.triangles[2] = new IndexedVertexTriangle(wall.vertices, 3, 7, 6);
wall.triangles[3] = new IndexedVertexTriangle(wall.vertices, 3, 6, 2);
wall.triangles[4] = new IndexedVertexTriangle(wall.vertices, 7, 3, 0);
wall.triangles[5] = new IndexedVertexTriangle(wall.vertices, 7, 0, 4);
wall.triangles[6] = new IndexedVertexTriangle(wall.vertices, 5, 1, 2);
wall.triangles[7] = new IndexedVertexTriangle(wall.vertices, 5, 2, 6);
wall.triangles[8] = new IndexedVertexTriangle(wall.vertices, 0, 3, 2);
wall.triangles[9] = new IndexedVertexTriangle(wall.vertices, 0, 2, 1);
wall.triangles[10] = new IndexedVertexTriangle(wall.vertices, 7, 4, 5);
wall.triangles[11] = new IndexedVertexTriangle(wall.vertices, 7, 5, 6);

var vertices = [];

for (var i = 0; i < wall.triangles.length; i++) {
vertices[9 * i] = wall.vertices[wall.triangles[i].index1].elements[0];
vertices[9 * i + 1] = wall.vertices[wall.triangles[i].index1].elements[1];
vertices[9 * i + 2] = wall.vertices[wall.triangles[i].index1].elements[2];
vertices[9 * i + 3] = wall.vertices[wall.triangles[i].index2].elements[0];
vertices[9 * i + 4] = wall.vertices[wall.triangles[i].index2].elements[1];
vertices[9 * i + 5] = wall.vertices[wall.triangles[i].index2].elements[2];
vertices[9 * i + 6] = wall.vertices[wall.triangles[i].index3].elements[0];
vertices[9 * i + 7] = wall.vertices[wall.triangles[i].index3].elements[1];
vertices[9 * i + 8] = wall.vertices[wall.triangles[i].index3].elements[2];
}

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

wall.vertexPositionBufferID.itemSize = 3;
wall.vertexPositionBufferID.numItems = wall.triangles.length * 3;
}

function FpsCounter() {
this.count = 0;
this.fps = 0;
this.prevSecond;
this.minuteBuffer = new OverrideRingBuffer(60);
}

FpsCounter.prototype.update = function() {
if (!this.prevSecond) {
this.prevSecond = new Date().getTime();
this.count = 1;
}
else {
var currentTime = new Date().getTime();
var difference = currentTime - this.prevSecond;
if (difference > 1000) {
this.prevSecond = currentTime;
this.fps = this.count;
this.minuteBuffer.push(this.count);
this.count = 0;
}
else {
this.count++;
}
}
};

FpsCounter.prototype.getCountPerMinute = function() {
return this.minuteBuffer.getAverage();
};

FpsCounter.prototype.getCountPerSecond = function() {
return this.fps;
};

function OverrideRingBuffer(size) {
this.size = size;
this.head = 0;
this.buffer = new Array();
}
;

OverrideRingBuffer.prototype.push = function(value) {
if (this.head >= this.size)
this.head -= this.size;
this.buffer[this.head] = value;
this.head++;
};

OverrideRingBuffer.prototype.getAverage = function() {
if (this.buffer.length === 0)
return 0;

var sum = 0;

for (var i = 0; i < this.buffer.length; i++) {
sum += this.buffer[i];
}

return (sum / this.buffer.length).toFixed(1);
};

glpsutilskap8.js

function createPerspectiveMatrix(fFoVVy, 
fAspect,
fZnear,
fZfar) {
var test = (Matrix.create([
[fAspect / Math.tan(fFoVVy * Math.PI / 180.0), 0, 0, 0],
[0, 1 / Math.tan(fFoVVy * Math.PI / 180.0), 0, 0],
[0, 0, (fZnear + fZfar) / (fZnear - fZfar), 2 * fZnear * fZfar / (fZnear - fZfar)],
[0, 0, -1, 0]]));

return test;
return test;
}
;

Matrix.prototype.flatten = function() {
var result = [];
if (this.elements.length == 0)
return [];

for (var j = 0; j < this.elements[0].length; j++)
for (var i = 0; i < this.elements.length; i++)
result.push(this.elements[i][j]);
return result;
};


function initGL() {
canvas = document.getElementById("WebGL-canvas");
try {
gl = canvas.getContext("experimental-webgl");
}
catch (e) {
}

if (!gl) {
try {
gl = canvas.getContext("webgl");
}
catch (e) {
}
}

if (!gl) {
try {
gl = canvas.getContext("webkit-3d");
}
catch (e) {
}
}

if (!gl) {
try {
gl = canvas.getContext("moz-webgl");
}
catch (e) {
}
}
if (!gl) {
alert("WebGL not found. Please use an up to date browser and update your graphics driver.");
}
}

function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript)
return null;

var str = "";
var k = shaderScript.firstChild;
while (k) {

if (k.nodeType == 3)
str += k.textContent;
k = k.nextSibling;
}

var shader;
if (shaderScript.type == "x-shader/x-fragment") {

shader = gl.createShader(gl.FRAGMENT_SHADER);
}
else if (shaderScript.type == "x-shader/x-vertex") {

shader = gl.createShader(gl.VERTEX_SHADER);
}
else {

return null;
}

gl.shaderSource(shader, str);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

alert(gl.getShaderInfoLog(shader));
return null;
}

return shader;
}

function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");

shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}

gl.useProgram(shaderProgram);

// attributes
vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(vertexPositionAttribute);
}

function setMatrixUniforms() {
var mvpUniform = gl.getUniformLocation(shaderProgram, "mvpMatrix");
gl.uniformMatrix4fv(mvpUniform, false, new Float32Array(mvpMatrix.flatten()));
}

function IndexedVertexTriangle(vectorArray, index1, index2, index3)
{
this.index1 = index1;
this.index2 = index2;
this.index3 = index3;
this.vectorArray = vectorArray;
this.normal = null;
this.getNormal = function()
{
if (this.normal == null)
{
var sideOne = this.vectorArray[this.index2].subtract(this.vectorArray[this.index1]);
var sideTwo = this.vectorArray[this.index3].subtract(this.vectorArray[this.index1]);
this.normal = sideOne.cross(sideTwo);
this.normal = this.normal.toUnitVector();
}

return(this.normal);
};

this.getVertex = function(localIndex)
{
if (localIndex > 3)
{
return(0);
}
if (localIndex == 1)
return(this.vectorArray[index1]);
if (localIndex == 2)
return(this.vectorArray[index2]);
if (localIndex == 3)
return(this.vectorArray[index3]);
};
}

Vector.prototype.flatten = function()
{
var result = [];
if (this.elements.length == 0)
return [];


for (var i = 0; i < this.elements.length; i++)
result.push(this.elements[i]);
return result;
};

西尔维斯特.js

下载地址:http://sylvester.jcoglan.com/#download

编辑:

使用 Chrome 时间轴和其他东西:

  • 起初垃圾回收 (GC) 占用 25% 的 CPU,后来是 60%。

  • 每次 draw() 调用几乎都会发生一次 GC(清理 7.5mb)。大约每 20 次 draw() 调用就没有 GC。在大约 20 次没有 GC(约 400 次 draw() 调用)后,发生了更大的 GC (30-40mb)。

  • 堆分配快照:存在到最后的数据只在开始时分配一次。如预期的那样。

  • TestData 占堆的 94%。

所以,GC 出了点问题,但我仍然不知道是什么原因。是否有可能是因为 94% 的测试数据,chrome 使我的内存碎片过多?所以 GC 变慢了?

我会尝试更习惯使用这些工具并可能会发布更新,但仍将不胜感激。

最佳答案

终于找到问题所在:大多数浏览器的垃圾收集,尤其是 Chrome 在处理类型化数组时存在问题。

这是一个相关的 Chromium 错误: https://code.google.com/p/chromium/issues/detail?id=232415

要“修复”这个问题,只需使用普通数组而不是类型化数组:

旧代码:

function setMatrixUniforms() {
var mvpUniform = gl.getUniformLocation(shaderProgram, "mvpMatrix");
gl.uniformMatrix4fv(mvpUniform, false, new Float32Array(mvpMatrix.flatten()));
}

新代码:

function setMatrixUniforms() {
var mvpUniform = gl.getUniformLocation(shaderProgram, "mvpMatrix");
gl.uniformMatrix4fv(mvpUniform, false, mvpMatrix.flatten());
}

关于javascript - 为什么我的 WebGl 帧率在 Chrome 中缓慢下降?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23930743/

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