Это зависит от вашего определения async.
В Chrome (Firefox тоже может сделать это сейчас? Не уверен). Chrome запускает весь код графического процессора в отдельном процессе от JavaScript. Это означает, что ваши команды выполняются асинхронно. Даже сам OpenGL спроектирован как асинхронный. Функции (WebGL / OpenGL) вставляют команды в буфер команд. Они выполняются другим потоком / процессом. Вы говорите OpenGL: «Эй, у меня есть новые команды, которые нужно выполнить!» позвонив по телефону gl.flush
. Он выполняет эти команды асинхронно. Если вы не вызовете gl.flush
, он будет вызываться для вас периодически, когда будет введено слишком много команд. Он также будет вызываться при выходе из текущего события JavaScript, если вы вызвали любую команду рендеринга на холсте (gl.drawXXX, gl.clear).
В этом смысле все в WebGL асинхронно. Если вы не запрашиваете что-то (gl.getXXX, gl.readXXX), значит, обработка (рисование) материала не синхронизируется с вашим JavaScript. WebGL дает вам доступ к графическому процессору, который работает отдельно от вашего процессора.
Один из способов воспользоваться этим преимуществом в Chrome - это скомпилировать асинхронные шейдеры, отправив шейдеры.
for each shader
s = gl.createShader()
gl.shaderSource(...);
gl.compileShader(...);
gl.attachShader(...);
gl.linkProgram(...)
gl.flush()
Теперь процесс GPU будет компилировать ваши шейдеры. Итак, скажем, через 250 мс вы только тогда начинаете спрашивать, удалось ли это, и запрашивать местоположения, тогда, если для компиляции и связывания шейдеров потребовалось менее 250 мс, все это произошло асинхронно.
В WebGL2 есть по крайней мере еще одна явно асинхронная операция, запросы окклюзии, в которых WebGL2 может сказать вам, сколько пикселей было нарисовано для группы вызовов отрисовки. Если не было нарисовано, то ваши розыгрыши были закрыты. Чтобы получить ответ, вы периодически звоните, чтобы увидеть, готов ли ответ. Обычно вы проверяете следующий кадр, и на самом деле спецификация WebGL требует, чтобы ответ был недоступен до следующего кадра.
В противном случае на данный момент (август 2018 г.) явно асинхронных API нет.
Обновлять
HankMoody упомянул в комментариях, что texImage2D
синхронизируется. Опять же, это зависит от вашего определения асинхронности. Чтобы добавить команды и их данные, нужно время. Команда типа gl.enable(gl.DEPTH_TEST)
должна добавить только 2-8 байтов. Команда типа gl.texImage2D(..., width = 1024, height = 1024, RGBA, UNSIGNED_BYTE)
должна добавить 4 мегабайта !. После того, как эти 4 мегабайта загружены, все остальное выполняется асинхронно, но загрузка требует времени. То же самое для обеих команд, просто добавление 2-8 байтов занимает намного меньше времени, чем добавление 4 мегабайт.
Для большей ясности, после того, как загружаются 4 мегабайта, многие другие вещи происходят асинхронно. Драйвер называется с 4 мег. Драйвер копирует тот 4мег. Драйвер планирует использовать эти 4 мегабайта позже, так как он не может сразу загрузить данные, если текстура уже используется. Либо так, либо он сразу же загружает его просто в новую область, а затем меняет местами то, на что указывает текстура, непосредственно перед вызовом отрисовки, который фактически использует эти новые данные. Другие драйверы просто копируют данные, сохраняют их и ждут, пока текстура не будет использована в вызове отрисовки, чтобы фактически обновить текстуру. Это связано с тем, что texImage2D имеет сумасшедшую семантику, при которой вы можете загружать mip-файлы разного размера в любом порядке, поэтому драйвер не может знать, что на самом деле нужно в памяти графического процессора, до момента отрисовки, поскольку он не знает, в каком порядке вы собираетесь вызывать texIamge2D. Все, что упомянуто в этом абзаце, происходит асинхронно.
Но это дает дополнительную информацию.
gl.texImage2D
и связанные с ним команды должны сделать ТОННУ работы. Во-первых, они должны соблюдать UNPACK_FLIP_Y_WEBGL
и UNPACK_PREMULTIPLY_ALPHA_WEBGL
, поэтому им нужно сделать копию нескольких мегабайт данных, чтобы перевернуть или преумножить их. Во-вторых, если вы передадите им видео, холст или изображение, им, возможно, придется выполнить тяжелые преобразования или даже повторно проанализировать изображение из источника, особенно в свете UNPACK_COLORSPACE_CONVERSION_WEBGL
. Происходит ли это каким-либо асинхронным способом или нет, зависит от браузера. Поскольку у вас нет прямого доступа к изображению / видео / холсту, браузер может выполнять всю эту асинхронную работу, но так или иначе вся эта работа должна выполняться.
Чтобы сделать большую часть этой работы ASYNC, был добавлен ImageBitmap
API. Как и большинство веб-API, он недоопределен, но идея состоит в том, чтобы сначала выполнить fetch
(который является асинхронным). Затем вы запрашиваете создание ImageBitmap
и даете ему параметры для преобразования цвета, переворачивания, предварительно умноженного альфа-канала. Это тоже происходит асинхронно. Затем вы передаете результат gl.texImage2D
с надеждой, что браузер смог сделать все тяжелые части, прежде чем он перешел на этот последний шаг.
Пример:
// note: mode: 'cors' is because we are loading
// from a different domain
async function main() {
const response = await fetch('https://i.imgur.com/TSiyiJv.jpg', {mode: 'cors'})
if (!response.ok) {
return console.error('response not ok?');
}
const blob = await response.blob();
const bitmap = await createImageBitmap(blob, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none',
});
const gl = document.querySelector("canvas").getContext("webgl");
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
{
const level = 0;
const internalFormat = gl.RGBA;
const format = gl.RGBA;
const type = gl.UNSIGNED_BYTE;
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
format, type, bitmap);
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
}
const vs = `
uniform mat4 u_worldViewProjection;
attribute vec4 position;
attribute vec2 texcoord;
varying vec2 v_texCoord;
void main() {
v_texCoord = texcoord;
gl_Position = u_worldViewProjection * position;
}
`;
const fs = `
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D u_tex;
void main() {
gl_FragColor = texture2D(u_tex, v_texCoord);
}
`;
const m4 = twgl.m4;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 2);
const uniforms = {
u_tex: tex,
};
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.5;
const zFar = 10;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const eye = [1, 4, -6];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projection, view);
const world = m4.rotationY(time);
uniforms.u_worldViewProjection = m4.multiply(viewProjection, world);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
К сожалению, это работает только в Chrome с августа 2018 года. здесь в Firefox. Других браузеров я не знаю.
person
gman
schedule
07.08.2018