mistic100 / Photo-Sphere-Viewer

A JavaScript library to display 360° sphere panoramas.
https://photo-sphere-viewer.js.org
MIT License
1.88k stars 678 forks source link

WebGL contexts not being cleaned up on destroy() [chrome browser] #1438

Open AnonymousSausage77 opened 3 hours ago

AnonymousSausage77 commented 3 hours ago

Describe the bug

Users in my application can select different tours to visit (ie. virtual tour plugin) which they can select from a menu. When they do this enough in chrome, it errors.

When they choose a new tour, I am refreshing the whole plugin as follows:

I am using NextJS to control the lifecycle of my Photo Sphere Viewer instance. In a useEffect(), i am registering a new photo sphere viewer instance and then, on the cleanup of that useEffect, i am destroying the viewer by calling viewer.destroy(). Therefore, whenever the user closes and reopens the pano, this component remounts, the useEffect runs and the new viewer is recreated.

In my local dev environment, there is no issue in chrome; you can run this code no issue as many times in 'npm run dev' as you'd like. When built and deployed to my server, if you refresh more than 15 times, it crashes after ~15 times because the webgl contexts are not being destroyed despite my calling viewer.destroy(). I get:

fb7d5399.39fb0d39ba29a80f.js:230 WARNING: Too many active WebGL contexts. Oldest context will be lost. 9997.0a9e7fe6ff5d55aa.js:1 WebGL context lost fb7d5399.39fb0d39ba29a80f.js:230 WARNING: Too many active WebGL contexts. Oldest context will be lost. fb7d5399.39fb0d39ba29a80f.js:230 THREE.WebGLRenderer: Context Lost. fb7d5399.39fb0d39ba29a80f.js:230 WARNING: Too many active WebGL contexts. Oldest context will be lost. fb7d5399.39fb0d39ba29a80f.js:230 THREE.WebGLRenderer: Context Lost.

I know most browsers can only maintain 16 webgl context instances. I can only think of two things that this could mean:

Online demo URL

No response

Photo Sphere Viewer version

5.8.3

Plugins loaded

virtual-tour-plugin;equirectangular-tiles-adapter

OS & browser

Apple M2 Pro; 13.4 (22F66)

Additional context

Happens on build when on chrome (windows os), chrome (mac os).

Does not happen on firefox (mac os), nor on Safari (mac os)

To me, this seems like a chrome-related issue.

AnonymousSausage77 commented 2 hours ago

Ok, so, to attempt to fix this issue, i did something like:

// this does not rerender throughout my entire program

function Parent() {

    // while PSVWrapper may rerender, canvas does not which means
    // the webgl context should remain the same
    const canvas = useMemo(() => <canvas id="psv-canvas" />

    <PSVWrapper>
         {canvas}
    </PSVWrapper>
}

and then:


function PSVWrapper({children}) {

    useEffect(() => {

    // ....

      const canvasElement = document.getElementById("psv-canvas") as HTMLCanvasElement;
      const webGlContext = canvasElement.getContext("webgl2") || canvasElement.getContext("webgl");

      if (!webGlContext) {
        throw new Error("Failed to get webgl context")
      }

      const webglRendererParameters : WebGLRendererParameters = {
        canvas: canvasElement,
        context: webGlContext,
      }

      const newViewer = new PhotoSphereViewer({
        adapter: EquirectangularTilesAdapter,
        container: viewerContainerRef.current,
        zoomSpeed: 0.4,
        minFov: MIN_FOV,
        maxFov: MAX_FOV,
        rendererParameters: webglRendererParameters,

        navbar: false,
        plugins: [[VirtualTourPlugin, tourConfig]],
      });

      // ....

    }, [])

   return <div id="psv-container">
        {children}
    </div>

    }

But despite manually setting the webgl context and canvas to a value which does not change, when PSVWrapper is re-added to the dom (which causes PSV to reload), it still causes new webgl contexts to be created.... This tells me that the PSV threejs instance is not correctly accepting the passed-in webgl context which I am trying to give it. Instead, it is creating new ones.