Улучшение холст предварительного рендеринга


Я определяю мой холст, как обычно, но я также включают в себя кучу разных самодельных полотен:

var graphicOne = document.createElement("canvas");
var graphicOneDraw = graphicOne.getContext("2d");

// etc... (eg. graphicTwo)

Тогда я оставляю все эти полотна, вот так:

function preRender() {
  graphicOne.width = 24;
  graphicOne.height = 24;

  graphicOneDraw.beginPath();
  graphicOneDraw.fillStyle = '#0000ff';
  graphicOneDraw.arc(12, 12, 12, 0, Math.PI * 2, true);
  graphicOneDraw.fill();

  // etc... (eg. graphicTwo)
}

В главном цикле, мой игровой логики называется прежде чем я сделать его на холсте:

ctx.drawImage(graphicOne, player.x - 12, player.y - 12);

// etc... (eg. graphicTwo) and other things that needs to be rendered

Графика мне нужна, чтобы представить на самом деле больше ЦП/интенсивный ГПУ; это просто голая кость, так что вы получите суть. Но на вопрос: есть ли лучший способ пойти об этом?



193
-1
задан 9 апреля 2018 в 07:04 Источник Поделиться
Комментарии
1 ответ

Содержание Джит перевода

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

Некоторые предупреждения.

Очистить состояние

Используя 2D-контекста, что его состояние будет поддерживаться. Будьте уверены, чтобы очистить состояние, когда вы больше не нужны как государство может занимать много памяти.

например

ctx.filter = url("#element-id"); // can consume lots of memory and if animated ongoing CPU/GPU resources
ctx.fillStyle = ctx.createPattern(ctx.canvas,"repeat"); // requires copy of source image
ctx.strokeStyle = ctx.createPattern(image,"repeat"); // requires copy of source image
ctx.font = "128px myFancyFont"; // a loaded font

ctx.beginPath(); // lets create a very long path
for(var i = 0; i < 10000; i ++) { ctx.lineTo(Math.random() * 100, Math.random() * 100) }
ctx.stroke(); // You may be done with the path but its still there
// ready for another stroke or fill

Все выше (и больше) требуют значительных ресурсов памяти. Они также предпочитают эти ресурсы должны быть легко доступны для GPU, так что если можно будет занимать процессор ОЗУ (тень от оперативной памяти)

Заканчивается свободное ГПУ ОЗУ-это самый большой убийца производительности для рендеринга в браузере, как он начинает менять и внешние ресурсы графического процессора оперативной памяти для завершения отрисовки (ГПУ автобус взбучку, или GPU ОЗУ обмолота). Делайте все возможное, чтобы сохранить использование как можно более низкой, всегда освобождая ненужные ресурсы.

Я хотел бы сделать некоторые изменения

function createAndRenderResource(renderFunc, ...args)
const img = document.createElement("canvas");
const ctx = img.getContext("2d");
img.width = 24;
img.height = 24;
ctx.save(); // save default low memory state
renderFunc(ctx, ...args); // add the content
ctx.restore(); // cleanup releasing any unneeded RAM or connected processes
return img; // you can not remove the 2D context once made
// it remains in memory
}

function render(ctx, color) {
ctx.beginPath();
ctx.fillStyle = color;
ctx.arc(12, 12, 12, 0, Math.PI * 2, true);
ctx.fill();
}

const images = [
createAndRenderResource(render,"red"),
createAndRenderResource(render,"green"),
createAndRenderResource(render,"blue"),
]

Полномочия двух

Размер холста может быть любым, изображение может быть любым. Но путь ГПУ провести изображений оптимизирован для очень быстрого доступа. Изображения всегда сохраняются в размерах, которые являются степенями 2 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096... и т. д.

Знать печать ноги памяти любого ресурса в ГПУ найти ближайший силу два выше ширины или высоты.

Например, 48 на 12 (576 пикселей) изображения будут занимать, ближайшего ширина-64, и ближайшей высота 16 64 на 16 (1024 пикселей) почти в два раза больше оперативной памяти, необходимого для хранения изображений в GPU памяти.

Мертвых пикселей.

Код, который вы дали создает полотно, 24 на 24 пикселей. Объем памяти на GPU, таким образом, 32 на 32 пикселей. 77% на пиксель мертвых (неиспользованный) оперативной памяти.

Вы можете сделать вещи лучше, используя один холст и рисунок несколько спрайтов для этого. Холст 128 на 128 может содержать 25 спрайтов, которые 24 на 24 и имеет комнату для одной границы пикселей между ними, чтобы остановить кровотечение из-за пиксель с линейным поиском. Это уменьшает мертвые Pixel скорость до ~14%

Примечание: той же мощности двух правило применяется к изображениям.

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

Для большого числа переменных размеров спрайтов использовать один холст у власти два размера я использовать подстановки спрайт как свойство, добавленные в изображения / холста используется, что хранит позицию и размер каждого спрайта.

// a sprite is {x,y,w,h} the position on the sprite sheet.
// sprites is an array of sprites. and spriteIndex is which to render
function drawSprite(img, spriteIndex, x,y){
const spr = img.sprites[spriteIndex];
ctx.drawImage(img, spr.x, spr.y, spr.w, spr.h, x, y, spr.w, spr.h);
}

Кстати, вы нарушаете Правила сайта codeReview не поставлялось рабочего кода, Вы дали пример того, что ваш код делает. Она является неполной и не функционирует.

2
ответ дан 10 апреля 2018 в 12:04 Источник Поделиться