Chrome 不断打印此警告:“Canvas2D:将 willReadFrequently 属性设置为 true 时,使用 getImageData 进行多个读回操作会更快。”。我检查了触发警告的代码,您可以看到我将 willReadFrequently 属性设置为 true。可能是什么问题?其他地方也有这个警告,但是 willReadFrequently 属性解决了它。
Chrome 104-108 中的问题肯定存在。顺便说一句,我在 WebWorker 中。这可能是 Chrome 的错误吗?
const offdesireCtx = offDesire.getContext("2d", { willReadFrequently: true });
if (!offdesireCtx) {
throw new Error("Desired OffscrenCanvas ctx undefined");
}
const offGetCtx = offGet.getContext("2d", { willReadFrequently: true });
if (!offGetCtx) {
throw new Error("Get OffscrenCanvas ctx undefined");
}
var imgd = offdesireCtx.getImageData(0, 0, tileSize, tileSize), pix = imgd.data; //Warning triggers
var imgdGet = offGetCtx.getImageData(0, 0, tileSize, tileSize), pixGet = imgdGet.data; //Warning triggers
正如 MDN 所说 关于
willReadFrequently
:
这将强制使用软件(而不是硬件加速)2D 画布,并且可以在频繁调用 getImageData() 时节省内存。
这意味着画布必须完全在 CPU 上创建、绘制和读取。默认情况下,调用
getContext
会提供 GPU 上画布缓冲区的句柄,如果该调用之前发生在该画布上,则该数据已经在 GPU 上,并且必须将其复制回 CPU,从而击败了绩效警告的目标。
我发现在我的例子中,我正在创建画布并在一个函数中写入它,然后返回画布。后来在我的代码中,该函数调用的结果采用相同的画布并创建了另一个上下文。它应用了 该调用的
{ willReadFrequently: true }
选项参数,但这是第二次为此画布调用 getContext
。这意味着此时纹理缓冲区已经存在于 GPU 上,并且第二个 getContext
调用忽略了 willReadFrequently
建议,因为数据已经在 GPU 上。
因此,您需要追溯到画布首次创建的位置,然后调用并绘制其第一个
getContext
的位置。随后的 canvas.getContext("2d", { willReadFrequently: true })
调用已经来不及了(甚至可以省略该选项)。考虑一下纹理缓冲区何时被创建并跟踪数据流,以确保它自启动以来全部都存在于 CPU 上。
围绕此警告还有一些启发。例如,Chrome 有时会根据某些条件自动从 GPU 渲染切换到 CPU 渲染。
参见https://www.schiener.io/2024-08-02/canvas-willreadfrequently