Обновление после комментариев HankMoody.
Я запустил это, и на самом деле потерянный контекст занял около 4 Гбайт при создании текстуры:
Total size = 4001366016
[Violation] 'setTimeout' handler took 427ms
WebGL: CONTEXT_LOST_WEBGL: loseContext: context lost
context lost; stopping now
context is lost
Это практически совпадает с информацией графического процессора, которую я могу получить от chrome://gpu
:
szDisplayMemoryEnglish 4163 MB
Если я правильно читаю, это означает, что у меня около 4 ГБ ОЗУ.
Интересно, что мне пришлось создать буфер (Float32Array) и передать его, иначе код будет работать вечно.
Итак, я не могу сказать, действительно ли GPU переставляет что-либо на процессор. Но у меня нет оснований полагать, что это так, поскольку я смог достичь пределов памяти моего графического процессора и заставить его перезагружаться.
Чтобы понять причины, по которым мы продолжаем терять контекст в нашем коде, я попытался смоделировать это, создавая текстуры на неопределенный срок, пока контекст не будет потерян.
Однако, независимо от того, как долго мой цикл продолжает создавать текстуры, я никогда не сталкивался с этой проблемой. Мой ноутбук перестает отвечать на запросы, но я никогда не вижу «потерянного контекста» в консоли Chrome.
Может ли графический процессор каким-то образом заменять память текстур памятью процессора?
Вот код, который я использую:
let contextLost = false;
function createCanvas(canvasWidth, canvasHeight) {
const canvas = document.createElement('canvas');
canvas.width = canvasWidth + 'px';
canvas.height = canvasHeight + 'px';
canvas.addEventListener("webglcontextlost", function(event) {
//event.preventDefault();
console.log('context is lost');
contextLost = true;
}, false);
canvas.addEventListener(
"webglcontextrestored", function() {
console.log('context is restored');
}, false);
return canvas;
}
function getGLContext(canvas) {
const attributes = { alpha: false, depth: false, antialias: false };
// Only fetch a gl context if we haven't already
const gl = canvas.getContext('webgl2', attributes);
if(!gl) {
throw 'No support for WebGL2';
}
if(!gl.getExtension('EXT_color_buffer_float')) {
throw 'No support for floatingpoint output textures';
}
return gl;
}
function createTexture(gl, width, height, data) {
const texture = gl.createTexture();
// Bind the texture so the following methods effect this texture.
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
// Pixel format and data for the texture
gl.texImage2D(
gl.TEXTURE_2D, // Target, matches bind above.
0, // Level of detail.
gl.R32F, // Internal format.
width, // Width - normalized to s.
height, // Height - normalized to t.
0, // Always 0 in OpenGL ES.
gl.RED, // Format for each pixel.
gl.FLOAT, // Data type for each chanel.
data); // Image data in the described format, or null.
// Unbind the texture.
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
}
let totalSize = 0;
const buffer = new Float32Array(1024*1024);
function createTexture2() {
const texsize=1024 * 1024 * 4;
const tex = createTexture(gl, 1024, 1024, buffer) ;
if(!tex || contextLost) {
console.log('context lost; stopping now');
return;
}
totalSize += texsize;
console.log('Total size = ' + totalSize);
window.setTimeout(createTexture2, 0);
}
const canvas = createCanvas(1,1);
const gl = getGLContext(canvas);
createTexture2();
console.log('the end');