OffscreenCanvas必须由主线程transferControlToOffscreen()创建并转移,Worker中直接new会报错;WebGL上下文在Worker中初始化失败主因是浏览器支持度与标志位限制,非代码错误。
不能直接在普通 Worker 里 new OffscreenCanvas(),必须由主线程转移控制权;WebGL 上下文能否在 Worker 中初始化,取决于浏览器和标志位,不是代码写错就是环境不支持。
普通 Worker 没有 DOM,new OffscreenCanvas(100, 100) 会报 TypeError: Illegal constructor。你看到的“Worker 中创建 OffscreenCanvas”其实是假象——真正路径只有一条:
<canvas id="gl-canvas"></canvas>
canvas.transferControlToOffscreen() 得到一个 OffscreenCanvas 实例postMessage(offscreencanvas, [offscreencanvas]),注意必须把实例放进 transfer list(第二个参数)getContext('webgl2')
漏掉 transfer list,对象会被序列化成空壳,getContext 静默返回 null,不会抛异常。
即使 transfer 成功,offscreen.getContext('webgl2') 仍可能为 null。这不是你 shader 写错了,而是环境限制:
dom.workers.offscreen-canvas.enabled 标志(about:config)验证方式很简单:console.log(offscreen.getContext('webgl2') !== null),别等渲染时报错才排查。
Worker 里没有 HTMLImageElement、fetch 返回的 Blob 也不能直接丢给 texImage2D。常见错误是:
<img src="a.png"> 进 Worker → drawImage(img, ...) → 触发同步回读,卡死主线程fetch('tex.png').then(res => res.blob()).then(blob => gl.texImage2D(...)) → texImage2D 不接受 Blob,会静默失败正确做法:
createImageBitmap(blob) 预解码,再 postMessage(imageBitmap, [imageBitmap])
gl.texImage2D(..., imageBitmap),零拷贝、GPU 友好想把渲染结果拿回主线程显示?别用 readPixels —— 它强制 GPU 同步,一帧卡几百毫秒。正确路径是:
offscreenCanvas.transferToImageBitmap()
postMessage(bitmap, [bitmap]),同样必须进 transfer listImageBitmap 后,用 ctx.drawImage(bitmap, ...) 或设为 background-image
注意:transferToImageBitmap() 是零拷贝操作;而 readPixels + createImageBitmap(new Uint8Array(...)) 是双重内存拷贝,性能灾难。如果真需要像素数据做分析,改用 WebGL2 的 TransformFeedback 异步采集,别碰 readPixels。