Возможно, вы сможете использовать EXT_disjoint_timer_query_webgl2
?
function main() {
const gl = document.createElement('canvas').getContext('webgl2', {
powerPreference: 'high-performance',
});
log(`powerPreference: ${gl.getContextAttributes().powerPreference}\n\n`);
if (!gl) {
log('need WebGL2');
return;
}
const ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
if (!ext) {
log('need EXT_disjoint_timer_query_webgl2');
return;
}
const vs = `#version 300 es
in vec4 position;
void main() {
gl_Position = position;
}
`;
const fs = `#version 300 es
precision highp float;
uniform sampler2D tex;
out vec4 fragColor;
void main() {
const int across = 100;
const int up = 100;
vec2 size = vec2(textureSize(tex, 0));
vec4 sum = vec4(0);
for (int y = 0; y < up; ++y) {
for (int x = 0; x < across; ++x) {
vec2 start = gl_FragCoord.xy + vec2(x, y);
vec2 uv = (mod(start, size) + 0.5) / size;
uv = texture(tex, uv).xy;
uv = texture(tex, uv).xy;
uv = texture(tex, uv).xy;
uv = texture(tex, uv).xy;
uv = texture(tex, uv).xy;
uv = texture(tex, uv).xy;
uv = texture(tex, uv).xy;
sum += texture(tex, uv);
}
}
fragColor = sum / float(across * up);
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);
const pixels = new Uint8Array(1024 * 1024 * 4);
for (let i = 0; i < pixels.length; ++i) {
pixels[i] = Math.random() * 256;
}
// creates a 1024x1024 RGBA texture.
const tex = twgl.createTexture(gl, {src: pixels});
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const waitFrame = _ => new Promise(resolve => requestAnimationFrame(resolve));
const widthHeightFromIndex = i => {
const height = 2 ** (i / 2 | 0);
const width = height * (i % 2 + 1);
return { width, height };
};
async function getSizeThatRunsUnderLimit(gl, limitMs) {
log('size time in milliseconds');
log('--------------------------------');
for (let i = 0; i < 32; ++i) {
const {width, height} = widthHeightFromIndex(i);
const timeElapsedMs = await getTimeMsForSize(gl, width, height);
const dims = `${width}x${height}`;
log(`${dims.padEnd(11)} ${timeElapsedMs.toFixed(1).padStart(6)}`);
if (timeElapsedMs > limitMs) {
return widthHeightFromIndex(i - 1);
}
}
}
(async () => {
const limit = 1000 / 20;
const {width, height} = await getSizeThatRunsUnderLimit(gl, limit);
log('--------------------------------');
log(`use ${width}x${height}`);
})();
async function getTimeMsForSize(gl, width, height) {
gl.canvas.width = width;
gl.canvas.height = height;
gl.viewport(0, 0, width, height);
// prime the GPU/driver
// this is voodoo but if I don't do this
// all the numbers come out bad. Even with
// this the first test seems to fail with
// a large number intermittently
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
for (;;) {
const query = gl.createQuery();
gl.beginQuery(ext.TIME_ELAPSED_EXT, query);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
gl.endQuery(ext.TIME_ELAPSED_EXT);
gl.flush();
for (;;) {
await waitFrame();
const available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
if (available) {
break;
}
}
const disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
if (!disjoint) {
const timeElapsed = gl.getQueryParameter(query, gl.QUERY_RESULT);
gl.deleteQuery(query);
return timeElapsed / (10 ** 6); // return milliseconds
}
gl.deleteQuery(query);
}
}
}
main();
function log(...args) {
const elem = document.createElement('pre');
elem.textContent = args.join(' ');
document.body.appendChild(elem);
}
pre { margin: 0; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
На моем Macbook Pro 2014 года с двумя графическими процессорами (Intel / Nvidia), во-первых, даже если я прошу высокопроизводительный Chrome, он дает мне низкое энергопотребление, что означает использование встроенного графического процессора Intel.
Первый тайминг на пикселях 1x1 часто составляет ~ 17 мс с перерывами и часто, но не всегда. Я не знаю, как это исправить. Я мог бы продолжать отсчет времени до тех пор, пока 1х1 пиксель не станет более разумным числом, например, 5 раз, пока он не станет <1 мс, и если никогда, то не сработает?
powerPreference: low-power
size time in milliseconds
--------------------------------
1x1 16.1
2x1 0.0
2x2 0.0
4x2 0.0
4x4 0.0
8x4 0.1
8x8 0.1
16x8 0.0
16x16 0.0
32x16 0.0
32x32 0.0
64x32 13.6
64x64 35.7
128x64 62.6
--------------------------------
use 64x64
Тестирование на Macbook Air конца 2018 года со встроенным графическим процессором Intel показало аналогичную проблему, за исключением того, что первое время оказалось еще хуже - 42 мс.
size time in milliseconds
--------------------------------
1x1 42.4
2x1 0.0
2x2 0.0
4x2 0.0
4x4 0.0
8x4 0.0
8x8 0.0
16x8 0.0
16x16 0.0
32x16 0.0
32x32 0.0
64x32 0.0
64x64 51.5
--------------------------------
use 64x32
Кроме того, тайминги являются фиктивными. Обратите внимание на мой MBP 2014 года, 32x32 - это 0 мс, а 64x32 - внезапно 13 мс. Я ожидал, что 32x32 будет 6.5 мс. То же самое с MBA выше, все 0, а затем внезапно 51 мс! ??! ??
Запускать его на рабочем столе Windows 10 с Nvidia RTX 2070 все кажется более разумным. Тайминги 1x1 правильные, и тайминги растут, как и ожидалось.
powerPreference: low-power
size time in milliseconds
--------------------------------
1x1 0.0
2x1 0.0
2x2 0.0
4x2 0.0
4x4 0.0
8x4 0.0
8x8 0.0
16x8 0.0
16x16 0.0
32x16 0.1
32x32 0.1
64x32 2.4
64x64 2.9
128x64 3.1
128x128 6.0
256x128 15.4
256x256 27.8
512x256 58.6
--------------------------------
use 256x256
Кроме того, во всех системах, если я не прорисовываю каждый размер заранее, он не работает, и все тайминги выходят ›16 мс. Добавление предварительного рисования вроде работает, но это вуду. Я даже пробовал предварительно рисовать только 1x1 пиксель вместо пикселей ширины на высоту в качестве предварительного рисования, и это не удалось!?!?!?
Кроме того, Firefox не поддерживает EXT_disjoint_timer_query_webgl2, я считаю, что это связано с тем, что точное время позволяет украсть информацию из других процессов. Chrome исправил это с помощью изоляции сайта, но я предполагаю, что Firefox еще этого не сделал. тот.
примечание: WebGL1 имеет EXT_disjoint_timer_query
для аналогичных функций.
обновление: проблемы с графическими процессорами Intel могут быть связаны с нечеткой синхронизацией, чтобы избежать проблем с безопасностью? Графические процессоры Intel используют единую память (то есть они разделяют память с ЦП). Я не знаю. В статье о безопасности Chrome упоминается снижение точности на устройствах с объединенной памятью.
Я полагаю, что даже без расширений времени вы могли бы попробовать проверить, сможете ли вы рендерить менее 60 Гц, проверив время requestAnimationFrame. К сожалению, мой опыт показывает, что это может быть нестабильно. Что угодно может привести к тому, что rAF будет принимать более 60 кадров в секунду. Возможно, пользователь запускает другие приложения. Может, они на мониторе 30 Гц. и т.д ... Возможно, усреднение таймингов по определенному количеству кадров или получение наименьшего значения из нескольких таймингов.
person
gman
schedule
24.08.2020