OffscreenCanvas + ThreeJS issue on Safari

736 Views Asked by At

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?

1

There are 1 best solutions below

0
Kaiido On

The issue is that, while Safari was ready to handle WebGL in OffscreenCanvas since 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 for OffscreenCanvas#getContext(), this page should probably remove it from their fallback list for OffscreenCanvas.