- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的 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/
我使用 QBFC v13 和 Delphi XE6。 目标是从我的应用程序创建 Estimate 并将其参数设置到 QuickBooks 中。 我从 QBFC13 导入类型库并将其添加到我的项目中。
我有一个数据库,其中有很多格式不正确的地址。在这个地址中,我只有一个街道地址或带有城市名称的街道。在我的应用程序中,用户选择一些类别,然后我想在 map 上显示例如 50,100,300 等地址。(不
在大多数软件项目中,缺陷源自需求、设计、编码和缺陷更正。根据我的经验,大多数缺陷都源于编码阶段。 我有兴趣了解软件开发人员使用哪些实用方法来降低缺陷注入(inject)率。 我已经看到以下方法的使用取
我正在使用实时 API 中的标签订阅构建一个应用程序,并且有一个与容量规划相关的问题。我们可能有大量用户同时发布到订阅的主题标签,因此问题是 API 实际发布到我们的订阅处理端点的频率是多少?例如,如
尝试使用 NULLIF 或 IFNULL 函数,但仍收到被零除的消息。 SELECT client_id ,COUNT(distinct CASE WHEN status = 'failed' THE
我目前正在开发一个使用 Django-rest-framework 制作的 API。我必须根据每个用户组设置限制率。 我们目前使用默认配置的 memcached 作为缓存后端,即按站点缓存。 在使用
我认为有时在神经网络(特别是一般对抗网络)训练期间改变丢失率可能是一个好主意,从高丢失率开始,然后线性地将丢失率降低到零。您认为这有意义吗?如果是的话,是否有可能在 tensorflow 中实现这一点
我有一个 Windows Server 2008,Plesk 运行着两个网站。有时服务器运行缓慢,并且有一个 named.exe 进程使 CPU 峰值达到 100%。它持续很短的时间,过一会儿它又来了
我正在使用 scikit-learn 随机森林分类器,我想通过将成功投票所需的树数量从大于 50% 增加到 75% 来降低 FP 率,在阅读文档后我不这样做确定如何做到这一点。有没有人有什么建议。 (
当我连续按下按键事件(字母 k)时,为什么以下按键事件不会减慢 3000 密耳?如果我按住手指,计数会迅速增加,因为 mcount 上没有 setTimeout。这是为什么?每次计数之间应该有延迟,但
我是一名优秀的程序员,十分优秀!