2

I'm continuing with my canvas hobby a-a-and hit another problem while trying to offload most of the things with web workers. This is the current design: [creating and starting the core web worker core.js from index.html]

  var canvas = document.getElementById('testcanvas');
  canvas.imageSmoothingEnabled = false;
  const offscreenCanvas = canvas.transferControlToOffscreen();

  const core = new Worker('core.js');

  //transfer offscreenCanvas just ONCE or will get a 'An OffscreenCanvas could not be cloned because it was detached' error
  core.postMessage({canvas: offscreenCanvas, msg: 'start'}, [offscreenCanvas]);

[in the core.js I'm creating two web workers]

'use strict'; //meh

const render = new Worker('render.js');

const mainloop = new Worker('mainloop.js');

onmessage = function(ev) {
  if (ev.data.msg === 'start') {
    mainloop.postMessage({msg: 'start'});
  }

  if (ev.data.canvas) {
    render.postMessage({canvas: ev.data.canvas}, [ev.data.canvas]);
  }

  if (ev.data.posX && ev.data.posY) {
    render.postMessage({posX: ev.data.posX, posY: ev.data.posY});
  }
}

each web worker sends the results to the core worker [mainloop.js]

'use strict';

var canvas;
var ctx;

var speed = 100;

var currentTime = 0; var timeDiff = 0; var lastTime = 0;
var timeProduct = 0; var dTime = 0; var timeScale = 1; var timeStep = 0.01;

var posX = 10; var posY = 10;

function main() {
  currentTime = performance.now();
  timeDiff = (Math.abs(currentTime - lastTime) * 0.001);
  dTime += Math.min(timeDiff, 1);
  timeProduct = timeStep * timeScale;

  while (dTime > timeProduct) {
    postMessage({posX: posX, posY: posY});
    dTime -= timeProduct;
  }

  lastTime = currentTime;

  posX += speed * timeDiff;
  posY += speed * timeDiff;

  if (posX > 500) posX = 10;
  if (posY > 500) posY = 10;

  requestAnimationFrame(main);
  //setTimeout(main, 0);
}

onmessage = function(ev) {
  if(ev.data.msg === 'start') {
    main();
  }
}

[render.js]

'use strict';

var canvas;
var ctx;

function draw(posX, posY) {
  //clear
  ctx.setTransform(1,0,0,1,0,0);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = "#000000";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  //draw
  ctx.beginPath();
  ctx.moveTo(posX, posY);
  ctx.ellipse(posX,
              posY,
              5,
              5,
              0.7854,
              0,
              2 * Math.PI,
              false);
  ctx.strokeStyle = "white";
  ctx.stroke();
}

onmessage = function(ev) {
  if(ev.data) {
    if (!canvas) canvas = ev.data.canvas;
    if (!ctx) ctx = canvas.getContext('2d');
    draw(ev.data.posX, ev.data.posY);
  }
}

The problem is that when requestAnimationFrame(main) is called in the mainloop.js I'm receiving 'requestAnimationFrame not supported in this Worker' though offscreenCanvas has been transfered between core and render workers. When changed with setTimeout(main, 0) error disappears but nothing is drawn on the canvas ...

1000Gbps
  • 1,455
  • 1
  • 29
  • 34
  • 1
    see [documention™](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers) for what is/is not available in a Worker – Jaromanda X Sep 12 '19 at 21:40
  • 2
    Ok, it seems creating a web workers inside a web worker is supported by Chrome (my current browser) and Firefox. In fact FF latest dev edition gives `'canvas.transferControlToOffscreen is not a function'` error – 1000Gbps Sep 12 '19 at 21:47
  • a worker created by a worker would still not be able to use requestAnimationFrame if requestAnimationFrame is not available to workers – Jaromanda X Sep 12 '19 at 21:49
  • That's why I tried with `setTimout` as fallback and as I said without a success – 1000Gbps Sep 12 '19 at 21:55
  • have you read the documentation for offscreencanvas? for Firefox, you need to enable it in about:config – Jaromanda X Sep 12 '19 at 23:16
  • From what I can see, `requestAnimationFrame` is only available in Chrome workers, `offScreenCanvas` is only available in Firefox if enabled in about:config, and the only rendering context available in `offScreenCanvas` seems to be `webgl` - so, trying to use rendering context `2d` in a worker appears doomed – Jaromanda X Sep 12 '19 at 23:46
  • Seems you're right ... After enabling it FF said `NS_ERROR_NOT_IMPLEMENTED` for `getContext('2d')`. The only solution is to return to workers created directly in the global scope. This is hilarious and crazy – 1000Gbps Sep 13 '19 at 02:05
  • @JaromandaX Any ideas how to overcome this without returning the workers in the main thread and without `webgl` context?? – 1000Gbps Sep 14 '19 at 07:46
  • it's only render.js you'd move to the "main thread" – Jaromanda X Sep 14 '19 at 09:20
  • 1
    Firefox added support for requestAnimationFrame and cancelAnimationFrame in workers in v97, see https://bugzilla.mozilla.org/show_bug.cgi?id=1738971#c17 – Christopher Jun 10 '22 at 23:53

0 Answers0