我想知道是否有任何对WebGL的异步调用可以利用?
我已经调查了Spec v1和Spec v2,他们没有提到任何东西。在V2中,有一个WebGL查询机制,我认为这不是我想要的。
网络上的搜索并没有产生任何决定性的结果。有此示例,尚不清楚同步和异步版本有何不同。http://toji.github.io/shader-perf/
最后,我希望能够异步地处理所有这些:
有一个glFinish操作,它的文档说:“直到所有以前称为GL命令的效果完成后才返回。”对我来说,这意味着有一些异步操作可以通过调用Finish()来等待。
网络上的一些帖子建议,调用getError()也会强制一些同步性,在每次调用之后,并不是很想要做的事情。
发布于 2018-08-07 00:17:21
这取决于您对异步的定义。
在Chrome中(Firefox现在也会这么做吗?)不确定)。Chrome在一个独立于JavaScript的进程中运行所有GPU代码。这意味着您的命令正在异步运行。甚至OpenGL本身也被设计为异步的。函数(WebGL/OpenGL)将命令插入到命令缓冲区中。这些线程/进程由其他线程/进程执行。你告诉OpenGL“嘿,我有新命令要你执行!”打电话给gl.flush。它异步执行这些命令。如果不调用gl.flush,则会在发出太多命令时定期调用它。当当前JavaScript事件退出时,它也将被调用,假设您调用画布的任何呈现命令(gl.drawXXX,gl.clear)。
从这个意义上说,关于WebGL的一切都是异步的。如果您不查询某些内容(gl.getXXX、gl.readXXX),则将处理(绘制)与JavaScript不同步的内容。WebGL允许您访问GPU,毕竟它是独立于CPU运行的。
了解这一点,在Chrome中利用它的一种方法是通过提交着色器来编译着色器异步
for each shader
s = gl.createShader()
gl.shaderSource(...);
gl.compileShader(...);
gl.attachShader(...);
gl.linkProgram(...)
gl.flush()GPU进程现在将编译您的着色器。因此,比如说,250 if之后,您才开始询问它是否成功并查询位置,然后如果编译和链接着色器所花费的时间少于250 if -这一切都是异步的。
在WebGL2中,至少有一个更清晰的异步操作,即阻塞查询,在该操作中,WebGL2可以告诉您一组绘图调用绘制了多少像素。如果没有画,那么你的画就被挡住了。要想得到答案,你必须周期性地去看答案是否已经准备好了。通常,您需要检查下一个帧,实际上,WebGL规范要求在下一个帧之前无法得到答案。
否则,目前(2018年8月)还没有显式异步API。
更新
HankMoody在评论中提到texImage2D是同步的。同样,它的取决于异步的定义。添加命令及其数据需要时间。像gl.enable(gl.DEPTH_TEST)这样的命令只需要添加2-8字节。像gl.texImage2D(..., width = 1024, height = 1024, RGBA, UNSIGNED_BYTE)这样的命令必须添加4 4meg!一旦上传了这4meg,剩下的就是异步,但是上传需要时间。这对于两个命令来说都是一样的,只是添加2-8字节比添加4meg花费的时间要少得多。
更清楚的是,在上传了4 meg之后,其他许多事情都是异步发生的。司机和4 meg一起被调用。司机复印了那个4兆。驱动程序计划在稍后某个时候使用该4 4meg,因为如果纹理已经在使用,它就不能立即上传数据。或者它会立即上传到一个新的区域,然后在实际使用新数据的抽签调用之前交换纹理指向的内容。其他驱动程序只需复制数据并将其存储起来,直到纹理在抽签调用中被使用才能真正更新纹理。这是因为texImage2D有着疯狂的语义,您可以按任何顺序上传不同大小的mips,因此驱动程序在绘制时间之前无法知道GPU内存中实际需要什么,因为它不知道要调用texIamge2D的顺序。本段中提到的所有这些事情都是异步发生的。
但这确实带来了更多的信息。
gl.texImage2D和相关命令必须做大量的工作。其中之一是他们必须尊重UNPACK_FLIP_Y_WEBGL和UNPACK_PREMULTIPLY_ALPHA_WEBGL,所以他们需要复制多个海量的数据来翻转或复制数据。其次,如果您传递给他们一个视频、画布或图像,他们可能需要进行大量的转换,甚至从源对图像进行修复,特别是在考虑到UNPACK_COLORSPACE_CONVERSION_WEBGL的情况下。这是否以某种类似异步的方式发生取决于浏览器。由于您无法直接访问图像/视频/画布,所以浏览器可以完成所有这些异步操作,但是必须以某种方式完成所有这些工作。
为了完成这些工作,ASYNC添加了ImageBitmap API。与大多数Web一样,它是未指定的,但其思想是首先执行一个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>
不幸的是,这只适用于2018年8月的Chrome。火狐臭虫来了。其他我不知道的浏览器。
https://stackoverflow.com/questions/51710067
复制相似问题