最大限度地提高WebGL2的使用率,而不会使其过载

最大限度地提高WebGL2的使用率,而不会使其过载,webgl,webgl2,Webgl,Webgl2,我的web应用程序进行了很长的计算,然后给出了结果。我正在使用WebGL2进行计算-绘制到屏幕外 二维纹理。我不能简单地在一个WegGL调用中完成这项工作——计算时间太长,会导致“丢失上下文”错误。 因此,我将计算分为矩形部分,每个部分都可以在短时间内绘制出来 问题是如何安排这些WebGL调用。如果我经常这样做,浏览器可能会变得没有响应,或者带走我的WebGL上下文。 如果我不经常这样做,计算将花费比必要的更长的时间。 我明白偶尔失去上下文是正常的,我害怕系统性地失去它,因为我使用GPU太多了

我的web应用程序进行了很长的计算,然后给出了结果。我正在使用WebGL2进行计算-绘制到屏幕外 二维纹理。我不能简单地在一个WegGL调用中完成这项工作——计算时间太长,会导致“丢失上下文”错误。 因此,我将计算分为矩形部分,每个部分都可以在短时间内绘制出来

问题是如何安排这些WebGL调用。如果我经常这样做,浏览器可能会变得没有响应,或者带走我的WebGL上下文。 如果我不经常这样做,计算将花费比必要的更长的时间。 我明白偶尔失去上下文是正常的,我害怕系统性地失去它,因为我使用GPU太多了

我能想到的最好的办法是有一些工作与睡眠的比率,睡眠时间只占我计算时间的一小部分。我想 我可以使用WebGL2同步对象来等待发出的调用完成,并粗略估计它们花费了多少时间。像这样:

var workSleepRatio = 0.5; // some value
var waitPeriod = 5;
var sync;
var startTime;

function makeSomeWebglCalls() {
    startTime = performance.now();
    sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
    for (<estimate how many rectangles we can do so as not to waste too much time on waiting>) {
        gl.drawArrays(); // draw next small rectangle
    }
    setTimeout(timerCb, waitPeriod);
}

function timerCb() {
    var status = gl.getSyncParameter(sync, gl.SYNC_STATUS);
    if (status != gl.SIGNALED) {
        setTimeout(timerCb, waitPeriod);
    } else {
        gl.deleteSync(sync);
        
        var workTime = performance.now() - startTime;
        setTimeout(makeSomeWebglCalls, Math.min(1000, workTime * workSleepRatio));
    }
}

makeSomeWebglCalls();
var workSleepRatio=0.5;//一些价值
var-waitPeriod=5;
var同步;
var startTime;
函数makeSomeWebglCalls(){
startTime=performance.now();
sync=gl.fenceSync(gl.sync\u GPU\u命令完成,0);
对于(){
gl.drawArrays();//绘制下一个小矩形
}
设置超时(timerCb,waitPeriod);
}
函数timerCb(){
var status=gl.getSyncParameter(同步,gl.sync\u状态);
如果(状态!=总帐已发信号){
设置超时(timerCb,waitPeriod);
}否则{
总账删除同步(同步);
var workTime=performance.now()-startTime;
setTimeout(makeSomeWebglCalls,Math.min(1000,workTime*workSleepRatio));
}
}
makeSomeWebglCalls();
这种方法不是很好,存在以下问题:

  • 不知道如何设置workSleepRatio
  • 在gpu工作完成和计时器回调之间浪费时间。无法依赖gl.clientWaitSync,因为它的超时参数在许多浏览器中受零限制,即使在Web工作线程中也是如此
  • 无论我设置了多大的工作范围,我仍然不能确定浏览器是否会认为我做得太多,并带走了WebGL上下文。也许可以使用requestAnimationFrame在节流时减慢速度,但是用户在等待计算完成时无法切换选项卡
  • setTimeout可能会被浏览器限制,并且比请求的睡眠时间长得多
简言之,我有以下问题:

  • 如何利用WebGL既不超载又不浪费时间?这可能吗
  • 如果不可能,那么有没有更好的方法来处理这个问题

您是否可以使用

函数main(){
const gl=document.createElement('canvas').getContext('webgl2'{
powerPreference:“高性能”,
});
日志(`powerPreference:${gl.getContextAttributes().powerPreference}\n\n`);
如果(!gl){
日志(“需要WebGL2”);
返回;
}
const ext=gl.getExtension('ext_disjoint_timer_query_webgl2');
如果(!ext){
日志('needext\u disjoint\u timer\u query\u webgl2');
返回;
}
const vs=`#版本300 es
vec4位;
void main(){
gl_位置=位置;
}
`;
常数fs=`#版本300 es
高精度浮点;
均匀采样2d-tex;
out vec4 fragColor;
void main(){
横截常数int=100;
常数int up=100;
vec2 size=vec2(纹理化(tex,0));
vec4和=vec4(0);
对于(int y=0;ynewpromise(resolve=>requestAnimationFrame(resolve));
常数widthHeightFromIndex=i=>{
常数高度=2**(i/2 | 0);
常数宽度=高度*(i%2+1);
返回{宽度,高度};
};
异步函数GetSizeThatRunUnderLimit(gl、limitMs){
日志(“以毫秒为单位的大小时间”);
日志('--------------------------------------');
for(设i=0;i<32;++i){
常数{width,height}=widthHeightFromIndex(i);
const timelapsedms=等待getTimeMsForSize(gl、宽度、高度);
常量dims=`${width}x${height}`;
log(`dims.padEnd(11)}${timeElapsedMs.toFixed(1.padStart(6)}');
如果(timeElapsedMs>limitMs){
从索引返回的宽度和高度(i-1);
}
}
}
(异步()=>{
常数限值=1000/20;
const{width,height}=await GetSizeThatRunUnderLimit(gl,limit);
日志('--------------------------------------');
日志(`use${width}x${height}`);
})();
异步函数GetTimesForSize(总重、宽度、高度){
gl.canvas.width=宽度;
gl.canvas.height=高度;
总图视口(0,0,宽度,高度);
//初始化GPU/驱动程序
//这是巫毒,但如果我不这么做
//所有的数字都很糟糕,即使是
//第一次测试似乎失败了
//大量间歇地
总帐付款人(总帐三角形,6,总帐无符号_短,0);
对于(;;){
const query=gl.createQuery();
总账开始查询(外部时间\u经过\u外部,