Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] WebGL context already attached to device webgl-device-1 #9379

Open
1 of 7 tasks
finico opened this issue Jan 24, 2025 · 9 comments
Open
1 of 7 tasks

[Bug] WebGL context already attached to device webgl-device-1 #9379

finico opened this issue Jan 24, 2025 · 9 comments
Labels

Comments

@finico
Copy link

finico commented Jan 24, 2025

Description

After upgrading to version 9.1.0 deck crashes with an error
I use it with the react component - <DeckGL /> from @deck.gl/react

Flavors

  • Script tag
  • React
  • Python/Jupyter notebook
  • MapboxOverlay
  • GoogleMapsOverlay
  • CartoLayer
  • ArcGIS

Expected Behavior

No crash

Steps to Reproduce

https://stackblitz.com/edit/vitejs-vite-ecrh7kpz?file=src%2FApp.tsx

Environment

Logs

Error: WebGL context already attached to device webgl-device-1
    at new WebGLDevice (webgl-device.ts:169:13)
    at WebGLAdapter.create (webgl-adapter.ts:88:20)
    at async _Luma.createDevice (luma.ts:157:20)
    at async AnimationLoop._initDevice (animation-loop.ts:459:19)
    at async AnimationLoop.start (animation-loop.ts:179:9)
@finico finico added the bug label Jan 24, 2025
@Pessimistress
Copy link
Collaborator

Are you using StrictMode?

@finico
Copy link
Author

finico commented Jan 24, 2025

@Pessimistress yes.. but the error didn't happen until 9.1.0

@Pessimistress
Copy link
Collaborator

Yes, just trying to understand the cause.

@ibgreen in StrictMode context is initiated-finalized-initiated again on the same canvas.

@forseee
Copy link

forseee commented Jan 24, 2025

The same problem . Strict mode has no effect on anything ( Downgrade to v9.0.40 helped me

@ibgreen
Copy link
Collaborator

ibgreen commented Jan 25, 2025

I could imagine that the following fix could help, but what I am not so sure about is why it wasn't a problem in 9.0. Perhaps the Device class has undergone more changes than I remember.

I suppose someone who can repro this could try the fix quickly by adding the one line to webgl-device.js in your local luma.gl file in nodule_modules.

visgl/luma.gl#2320

@Pessimistress
Copy link
Collaborator

@ibgreen No, that does not fix the bug.

The first finalize() is called before the WebGLDevice constructor because luma.attachDevice() is asynchronous. device.destroy() is never hit.

In v9.0 WebGLDevice used to return the already attached device instead of throwing: https://github.com/visgl/luma.gl/blob/2068c74ce8b2417f64f4e80993ecf71085d2219d/modules/webgl/src/adapter/webgl-device.ts#L129-L132

You can reproduce this by modifying the get-started example:

- createRoot(container).render(<Root />);
+ createRoot(container).render(<React.StrictMode><Root /></React.StrictMode>);

@finico
Copy link
Author

finico commented Jan 25, 2025

Yes, Device::destroy() won't help so easily, because Device is created asynchronously and the moment of creation is always after double invocation of render and effects

ms event
474 render DeckGL
474 render DeckGL
475 effect createDeckInstance()
476 effect cleanup finalize() -- There is no Device to destroy it yet
476 effect createDeckInstance()
476 Device constructor
489 Device constructor
493 throws

If it is really so important not to attach WebGL context to a previously used Device, the best way is to create a new canvas, and cancel previous attach in cleanup, e.g. with AbortController

Or maybe, just maybe, make it a lot easier

diff a/react/src/deckgl.ts b/react/src/deckgl.ts
@@ -183,15 +183,20 @@
  useEffect(() => {
+   const timer = setTimeout(() => {
        const DeckClass = props.Deck || Deck;
        
        thisRef.deck = createDeckInstance(thisRef, DeckClass, {
            ...deckProps,
            parent: containerRef.current,
            canvas: canvasRef.current
        });
+   }, 0);

-   return () => thisRef.deck?.finalize();        
+   return () => {
+       clearTimeout(timer);
+       thisRef.deck?.finalize();
+   };
 }, []);

pros - do not create an instance unnecessarily (dev+StrictMode only, but still)
cons - looks a bit hacky

@ibgreen
Copy link
Collaborator

ibgreen commented Jan 25, 2025

Thanks for the good input everyone. I updated the PR. I'm adding a new experimental option DeviceProps._reuseDevices which Deck can opt into, to get the previous behavior without annoying warnings, but the default will remain that creating a device with a canvas' whose

In v9.0 WebGLDevice used to return the already attached device instead of throwing

I see what you mean,

  • however I find that it is going through the create path rather than the attach path.
  • As far I can tell, the attach path hasn't changed.
  • So, in createDevice we used to just return the existing attached device instead of the new one and issue a warning.

If it is really so important not to attach WebGL context to a previously used Device

In one sense is not so important, in that this feature mainly exists to support deck.gl's usage.

  • However it is not expected that two luma.gl devices successfully can reference the same WebGL context, so someone independently trying to work with multiple Devices could lose a lot of time debugging if we don't emit errors or at least warnings.
  • Also, it is my experience that these kind of workarounds tend to cause a long tail of "whack-a-mole" as surprising side effects from the reuse continue to pop up. Maintainers tend not to keep such edge cases in mind when refactoring things.

@imranrajjad
Copy link

Hi,

deck.ts:369  deck: WebGL1 context not supported.
Deck @ deck.ts:369
deck.ts:259  deck: Invalid WebGL2RenderingContext undefined
onError @ deck.ts:259
webgl-adapter.ts:54  Uncaught (in promise) Error: Invalid WebGL2RenderingContext
    at WebGLAdapter.attach (webgl-adapter.ts:54:13)
    at new Deck (deck.ts:371:39)
    at commons.ts:29:26
    at new Promise (<anonymous>)
    at createDeckInstance (commons.ts:28:10)
    at d.initializeResources (commons.ts:56:40)
    at d.attach (deck-layer-view-2d.ts:22:51)
    at n.<computed> [as attach] (4.17/:330:146)
    at VectorTileLayerView2D.js:161:283

Is this error related to this thread?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants