Skip to content

fallback to webgl on webgpu failures - #9191

Open
skyyash wants to merge 10 commits into
processing:mainfrom
skyyash:feat/webgl-fallback
Open

skyyash wants to merge 10 commits into
processing:mainfrom
skyyash:feat/webgl-fallback

Conversation

@skyyash

@skyyash skyyash commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Resolves #9175

Changes:

  1. src/core/rendering.js holds the two fallback paths. The sync path covers a missing addon. It corrects an old check that looked at the selectedRenderer instead of the requested one, so the warning actually fires now. The async path catches a rejected contextReady only when WEBGPU was requested, removes the failed canvas from _elements, builds a WebGL renderer with the same size and leftover args, and returns it. Other renderers still reject with Failed to create canvas.

  2. src/webgpu/p5.RendererWebGPU.js splits one error into four friendly errors. Missing navigator.gpu, null adapter, null device, and null canvas context.

  3. src/core/environment.js adds rendererType. Each constructor (
    src/core/p5.Renderer.js, src/webgl/p5.RendererGL.js and src/webgpu/p5.RendererWebGPU.js) assigns its type on the renderer and the sketch synchronously, which matters because WebGPU init is async and the old placement left p2d visible until the promise resolved.

PR Checklist

@skyyash
skyyash marked this pull request as ready for review September 18, 2026 07:16
@skyyash

skyyash commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

hi @davepagurek, src/core/p5.Renderer3D.js already catches use of webgpu only functions in non-webgpu renderers and logs friendly errors (which was stated as task in the issue). which also works when renderers falls back to webgl...

fn.createStorage = function (dataOrCount) {
    if (!this._renderer.createStorage) {
      p5._friendlyError(
        `createStorage() is only available with the WebGPU renderer. ${webGPUAddonMessage}`,
        'createStorage'
      );
      return;
    }
    return this._renderer.createStorage(dataOrCount);
  };

@p5-bot

p5-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown

Continuous Release

CDN link

Published Packages

Commit hash: 6760f7a

Previous deployments

c1cca8d


This is an automated message.

@perminder-17

Copy link
Copy Markdown
Collaborator

hi @davepagurek, src/core/p5.Renderer3D.js already catches use of webgpu only functions in non-webgpu renderers and logs friendly errors (which was stated as task in the issue). which also works when renderers falls back to webgl...

fn.createStorage = function (dataOrCount) {
    if (!this._renderer.createStorage) {
      p5._friendlyError(
        `createStorage() is only available with the WebGPU renderer. ${webGPUAddonMessage}`,
        'createStorage'
      );
      return;
    }
    return this._renderer.createStorage(dataOrCount);
  };

It's good that we already have an FES guard here, but FES doesn't stop execution. It only logs a message and the function returns undefined, so the sketch keeps running.

@davepagurek said in the issue that for buildComputeShader, createStorage and createStorageList we should

flag that immediately and fail early if you aren't in WebGPU mode.

If someone runs a sketch that uses these functions in a browser without WebGPU, the sketch will still execute, but none of the compute/storage work will actually happen. The user might get an FES message in the console, but the sketch will look like it's running while silently doing nothing. That could be confusing.

So I think we should throw an error here instead of only logging one, so the sketch fails at the first WebGPU-only call with a clear message.

Comment thread src/core/rendering.js Outdated
Comment on lines +184 to +187
this._renderer = new renderers[constants.WEBGL](this, w, h, true, ...args);
this._elements.push(this._renderer);
this._renderer._applyDefaults();
return this._renderer;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is what createCanvas() actually does in the code.

So instead of these, we can directly use this.createCanvas(w, h, constants.WEBGL, ...args);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm. yes, thanks for spotting that

Comment thread src/core/rendering.js Outdated
const failed = this._renderer;
try {
failed.remove();
} catch {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this also createCanvas() does above, so we can probably remove this one as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes but we should also remove failed renderer from this._elements, so i think i should put it above in createCanvas()

@perminder-17 perminder-17 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @skyyash, the code looks good so far. Do you have any test results, a short video or screenshot of the fallback running with WebGPU disabled? That would help me confirm it works end to end.

@skyyash

skyyash commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

hi @perminder-17 , here is the video...

fallback.mp4

on using webgpu only functions in non-webgpu renderer, the execution is stopped but the loader keeps running because control never reaches postsetup in src/core/main.js at L278.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebGPU-to-WebGL fallback

2 participants