как правильно очистить контекст WebGL и всю связанную с ним память GPU? [Дубликат]

Официальный учебник Python 2 4.2. «for Statementments» говорит:

Если вам нужно изменить последовательность, которую вы повторяете во время цикла (например, для дублирования выбранных элементов), рекомендуется сначала сделать копию. Итерация по последовательности не подразумевает создание копии. Нотация среза делает это особенно удобным:

>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

, что и было предложено в: https://stackoverflow.com/a/1207427/895245

Документация Python 2 7.3. «Инструкция for» дает тот же совет:

Примечание: существует тонкость, когда последовательность изменяется контуром (это может произойти только для изменяемых последовательностей, т. Е. Списков ). Внутренний счетчик используется для отслеживания того, какой элемент используется далее, и это увеличивается на каждой итерации. Когда этот счетчик достигнет длины последовательности, цикл завершается. Это означает, что если пакет удаляет текущий (или предыдущий) элемент из последовательности, следующий элемент будет пропущен (поскольку он получает индекс текущего элемента, который уже был обработан). Аналогично, если пакет вставляет элемент в последовательность перед текущим элементом, текущий элемент будет обрабатываться снова в следующий раз через цикл. Это может привести к неприятным ошибкам, которых можно избежать, создав временную копию, используя фрагмент всей последовательности, например

for x in a[:]:
    if x < 0: a.remove(x)

. Может ли Python сделать это лучше?

Кажется, что этот конкретный API Python может быть улучшен. Сравните его, например, со своим Java-партнером ListIterator , что делает его совершенно ясным, что вы не можете изменить список, который выполняется итерацией, за исключением самого итератора, и дает вам эффективные способы сделать это без копирования списка , Давай, Питон!

8
задан Bartvds 11 May 2014 в 23:07
поделиться

2 ответа

Вы можете просто потерять все ссылки на ваш gl-контекст и все объекты gl и холст и удалить холст из DOM. К сожалению, поскольку JavaScript-сборщик мусора не знает, когда браузер действительно освободит память. Есть несколько тестов соответствия, чтобы попытаться проверить, что они делают это правильно, но если вы не хотите просто надеяться и молиться тогда ....

Чтобы освободить все ваши ресурсы, вызвав gl.deleteXXX на все, что вы создал и отвязал все точки привязки. Это означает, что для каждой текстурной единицы вызывается gl.bindTexture для всех целей с нулевым значением, то же самое с массивами, фреймбуфферами и рендерингами.

var numTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
for (var unit = 0; unit < numTextureUnits; ++unit) {
  gl.activeTexture(gl.TEXTURE0 + unit);
  gl.bindTexture(gl.TEXTURE_2D, null);
  gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
}
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);

// Delete all your resources
// Note!!!: You'd have to change this code to delete the resources YOU created.
gl.deleteTexture(someTexture);
gl.deleteTexture(someOtherTexture);
gl.deleteBuffer(someBuffer);
gl.deleteBuffer(someOtherBuffer);
gl.deleteRenderbuffer(someRenderbuffer);
gl.deleteFramebuffer(someFramebuffer);

Поскольку вы не можете привязать нуль к атрибуту, вы можете установить размер всех ваших буферов до 1 (ноль не разрешен), прежде чем вы удалите их. Либо это, либо создайте новый буфер и назначьте его всем атрибутам.

Пример первого

// set a buffer to 1 byte before deleting
// NOTE: You'd need to do this for ALL BUFFERS you created.
gl.bindBuffer(gl.ARRAY_BUFFER, someArrayBuffer);
gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW);
gl.deleteBuffer(someArrayBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, someElementArrayBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 1, gl.STATIC_DRAW);
gl.deleteBuffer(someElementArrayBuffer);

Или создайте новый буфер и назначьте его всем атрибутам

var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
var numAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
for (var attrib = 0; attrib < numAttributes; ++attrib) {
  gl.vertexAttribPointer(attrib, 1, gl.FLOAT, false, 0, 0);
}

Это отвяжет старые буферы от атрибутов.

Наконец, установите размер холста в 1x1 пиксель.

gl.canvas.width = 1;
gl.canvas.height = 1;

Это не идеальное решение, но оно будет немедленно освободите все, кроме нескольких килобайт памяти, не дожидаясь сбора мусора, который не поддается контролю.

Что касается повторного использования холста с нуля, вы не можете. Холст всегда будет иметь тот же контекст, который вы его сначала попросили.

Также см. Ответ @ Johan о loseContext

14
ответ дан gman 1 September 2018 в 07:38
поделиться

Чтобы потерять контекст, используйте расширение WEBGL_lose_context как

gl.getExtension('WEBGL_lose_context').loseContext();

См. https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_lose_context/loseContext

4
ответ дан None 1 September 2018 в 07:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: