cesium icon indicating copy to clipboard operation
cesium copied to clipboard

webgl context is not released when destroy viewer!

Open wangzwswip opened this issue 2 years ago • 7 comments

Sandcastle example: create two viewer instances in one page. and then destroy on of them and rebuild. After 16 times will throw developError ' DeveloperError: Expected width to be greater than 0, actual value was 0 '. Chrome allow create 16 webgl context. fix: Modify the Context class destroy method, append this._gl.getExtension('WEBGL_lose_context').loseContext(). This error will disappear. I'm not sure this is the best way to fix this problem.

Browser: Chrome

Operating System: windows 11

wangzwswip avatar Sep 21 '23 08:09 wangzwswip

Hi there, I believe this is a duplicate of https://github.com/CesiumGS/cesium/issues/5991. I'm going to close this issue and add your report there to keep conversation in one place. Thanks!

ggetz avatar Sep 21 '23 14:09 ggetz

Gabby, I'm not sure it's actually a dupe. #5991 is about a helpful error message when the context is lost, this is about failing to clean up a resource, if I read it correctly.

thw0rted avatar Sep 21 '23 14:09 thw0rted

yes, this is about failing to clean up a resource.

wangzwswip avatar Sep 22 '23 10:09 wangzwswip

Got it, thanks @wangzwswip and @thw0rted!

ggetz avatar Sep 22 '23 13:09 ggetz

Also reported in https://github.com/CesiumGS/cesium/issues/12517.

ggetz avatar Mar 11 '25 20:03 ggetz

There is a thread in the community forum where multiple instances of this problem have been descibed: https://community.cesium.com/t/expected-width-to-be-greater-than-0-actual-value-was-0-error/7984

As I mentioned in my first response there: The error is very common, and can have many reasons - which leads to people websearching the error message, ending up in this thread, and chiming in. But in the latest reports, "the plot thickens" that the problem is really and only caused by the context not being destroyed (maybe really just the viewer not calling context.destroy() at the right place...)

javagl avatar Apr 06 '25 13:04 javagl

Also reported in https://github.com/CesiumGS/cesium/issues/12652 with usage with react routing.

ggetz avatar Jun 12 '25 18:06 ggetz

context.getExtension('WEBGL_lose_context').loseContext() seems to be the context.destroy() we're looking for.

Based on an example (link) shared in the community forum which reproduces the issue, I made some changes (link) which manually do this before destroying the viewer. (edited (twice) to fix the second sandcastle link)

 function dialogClose() {
+  let context = viewer2.canvas.getContext('webgl2') ??
+    viewer2.canvas.getContext('webgl'); // There may be a better way to retrieve the context
+  context?.getExtension('WEBGL_lose_context')?.loseContext()
   viewer2.destroy()
   viewer2 = null
   dialog.classList.remove('show')
 }

This seemed to prevent the crash.

ethanchristensen01 avatar Jun 25 '25 19:06 ethanchristensen01

I didn't dive into the details here (yet), but loseContext was already mentioned in the first post. Looking at the documentation I doubted that this is the right approach: It says

The WEBGL_lose_context.loseContext() method is part of the WebGL API and allows you to simulate losing the context of a WebGLRenderingContext context.

(Emphasis by me)

Now, why should "simulating" help here? (And what is the context of a context context after all? 🤪 )

But when looking at the specification, it says

This is the recommended mechanism for applications to programmatically halt their use of the WebGL API.

Even though it may also not be clear what that means (without reading the whole WebGL spec), this ambiguity can be handled in the happy engineer's way: Try it out an see what happens.

And what happens is: It works. 🤷‍♂


But... it's only a workaround. The fact that is is necessary probably indicates a (possibly deeply hidden) resource management issue in CesiumJS. I think that the clean way of destroying a context is to meticulously clean up each and every object that was allocated and unbind everything that was bound, and then ... ... ... well, cross fingers that the garbage collector deems the context as "garbage". Maybe some programmatic "reset-it-all" function (similar to the one in the WebGLDeveloperTools) could be an alternative, but certainly involves much more effort...)

javagl avatar Jun 25 '25 22:06 javagl

I tried this change out locally, and it seemed to work.

The fact that is is necessary probably indicates a (possibly deeply hidden) resource management issue in CesiumJS.

Yeah, this really is just a bandaid solution. I tried searching through the codebase for where else we might be missing some call to destroy, but I couldn't find anything unfortunately.

ethanchristensen01 avatar Jun 25 '25 23:06 ethanchristensen01

Adding my two cents:

  • I can only reproduce the issue in Chrome, not Firefox.
  • As @javagl said, the Khronos spec explicitly calls out the .lostContext() function as being for testing, so I don't think we should be using it in production (even as a bandaid?)
  • The number 16 feels a little too conspicuous - looking at https://webglreport.com/, the max number of texture slots available is 16. My guess is that these are being exhausted / not released on destroying the viewer. If I'm right, that narrows the search space down a lot.

mzschwartz5 avatar Jul 29 '25 14:07 mzschwartz5

context.getExtension('WEBGL_lose_context').loseContext()似乎就是context.destroy()我们正在寻找的。

根据社区论坛中分享的重现该问题的示例(链接) ,我做了一些更改(链接),在销毁查看器之前手动执行此操作。(编辑(两次)以修复第二个沙堡链接)

function dialogClose() {

  • let context = viewer2.canvas.getContext('webgl2') ??
  • viewer2.canvas.getContext('webgl'); // There may be a better way to retrieve the context
  • context?.getExtension('WEBGL_lose_context')?.loseContext() viewer2.destroy() viewer2 = null dialog.classList.remove('show') } 这似乎可以防止事故发生。 这个测试了并没有解决

junglelan avatar Sep 24 '25 08:09 junglelan