Browser CAN';从setTimeout更新画布时不会出现屏幕撕裂

Browser CAN';从setTimeout更新画布时不会出现屏幕撕裂,browser,html5-canvas,vsync,Browser,Html5 Canvas,Vsync,我发现了这个老问题,无法重现所描述的问题。 从setTimeout回调更新canvas会导致屏幕撕裂,这是有道理的。但即使闪烁非常明显,似乎也不会发生撕裂。这里有一个小演示:我看不到Chrome和Safari有任何漏洞。当然,浏览器不会对setTimeout执行VSync。所以这里发生了什么?我在画布更新中添加了一个延迟,所以缓冲区交换可能更容易发生在更新的中间,但是这里没有运气。 const STRIPE\u WIDTH=50; 常数步长=4; 让canvas=document.create

我发现了这个老问题,无法重现所描述的问题。 从
setTimeout
回调更新
canvas
会导致屏幕撕裂,这是有道理的。但即使闪烁非常明显,似乎也不会发生撕裂。这里有一个小演示:
我看不到Chrome和Safari有任何漏洞。当然,浏览器不会对
setTimeout
执行VSync。所以这里发生了什么?
我在画布更新中添加了一个延迟,所以缓冲区交换可能更容易发生在更新的中间,但是这里没有运气。

const STRIPE\u WIDTH=50;
常数步长=4;
让canvas=document.createElement('canvas');
canvas.style.width='100%';
canvas.style.height='100%';
document.body.appendChild(画布);
设ctx=canvas.getContext('2d');
设pos=0;
函数render(){
clearRect(0,0,canvas.width,canvas.height);
let width=Math.ceil(canvas.width/STRIPE\u width)*STRIPE\u width;
ctx.fillStyle='黑色';
对于(i=pos;i0;i-=条纹宽度){
对于(j=0;jrender()是的,画布渲染仍然绑定到文档的渲染,其本身与监视器的v-sync同步,因此您不会看到任何撕裂

您可以通过将上下文属性设置为
true
来禁用此功能

const low_latency_ctx=canvas.getContext(“2d”,{dessynchronized:true});

然而,目前只有ChromeOS和Windows上的Chrome支持这一点。由于我手头没有这样的配置,很遗憾我自己无法编写演示…

我明白了,但即使画布渲染与监视器同步,画布更新也不能。由于
setTimeout
callback独立于VSync更新后缓冲区,因此在后缓冲区未完全绘制的情况下,可以进行缓冲区交换。我认为没有撕裂的真正原因是我一次(在一次回调中)填满了整个画布<代码>设置超时
回调在主线程上执行,并阻止所有其他操作。我猜缓冲区交换也会发生在主线程上,因此会被阻塞,直到回调完成。因此,当交换发生时,整个后台缓冲区都被更新了。我编写了另一个演示,它将一个大的画布更新分解成小块,并在这些更新之间释放主线程。我不知道取消同步的
属性,谢谢。不幸的是,我也没有办法尝试。“缓冲区交换可以在后台缓冲区未完全绘制的情况下发生”,不,不能。缓冲区交换就是渲染,这与VSync同步进行。在启用VSync的配置上,以及在大多数常见的浏览器上,不能从画布进行撕裂。您可以从视频中进行撕裂,因为它们使用其他渲染路径,您可以通过使用支持配置上的
dessynchronized
属性进行撕裂,但仅此而已。当然你可以这样撕扯,但你不可能从画布上真正撕扯。对不起,我这样说可能会误导你。我的意思是,即使浏览器的帧与监视器的帧同步,
setTimeout
callback也与它们不同步。这将产生交换发生在回调执行的中间的可能性。由于回调正在更新画布,因此一些更新可能发生在交换之前,而另一些则发生在交换之后。这看起来像是撕裂,但我相信撕裂是不存在的,因为当主线程繁忙时,交换不能发生。它可能正忙于处理回调。因此,在回调执行期间不能进行交换,并且浏览器/监视器帧是重复的。当它最终发生时,回调已经完成了所有更新。解释我的意思