I'm having a strange issue with a ThreeJS scene in an OffscreenCanvas, but only with Safari. I create the OffscreenCanvas with this code:
let canvasElm = g('avatar-canvas');
const offscreen = canvasElm.transferControlToOffscreen();
console.log('renderWorker');
renderWorker = new Worker(new URL('workers/render-worker.js', import.meta.url), { type: 'module' });
renderWorker.mainThreadCtx = this;
renderWorker.postMessage(
{
task: 'prepareWorld',
canvas: offscreen,
worldParams: worldParams,
canvasSize: { width: container.offsetWidth, height: container.offsetHeight },
},
[offscreen],
);
and then in my web worker, I have:
function prepareWorld(data) {
canvas = data.canvas;
worldParams = data.worldParams;
renderer = new THREE.WebGLRenderer({
canvas,
antialias: true,
alpha: true,
powerPreference: 'high-performance',
precision: 'mediump',
});
canvasSize.width = data.canvasSize.width;
canvasSize.height = data.canvasSize.height;
etc...
In Safari, I get the error
THREE.WebGLRenderer: Argument 1 ('contextType') to OffscreenCanvas.getContext must be one of: "2d", "webgl", "webgl2", "bitmaprenderer"
And investigating further, it's this line in WebGLRenderer.js inside of THREE that is returning null and shouldn't be:
const context = canvas.getContext( contextName, contextAttributes );
Apparently, getContext will return null if the canvas already has a context, but in this case it shouldn't and as far as I know, there's no way to check if it has one or not.
I can't share the project unfortunately, but this ThreeJS demo exhibits identical behaviour:
https://threejs.org/examples/webgl_worker_offscreencanvas.html
Can anyone help at all please?
The issue is that, while Safari was ready to handle WebGL in
OffscreenCanvassince a long time ago, its actual support relied on macOS Sonoma (released to public in Sep. 2023).So users on Sonoma will now see that example work correctly on their Safari.
For the records, the error you've seen is due to
"experimental-webgl"being an invalid argument forOffscreenCanvas#getContext(), this page should probably remove it from their fallback list forOffscreenCanvas.