WebGL + Canvas randomly going black [Helldive Difficulty]

TLDR: Can WebGL resources automatically be disposed by the brower/system without warning?

I'm in a bit of a pickle. I have a Svelte project that acts as an image viewer and it uses an external library for rendering the images to a
<canvas />
with WebGL. The user can pan, zoom, draw annotations, change brightness and contrast, etc. The problem is a small number of users are reporting an issue where the "viewer" randomly goes black and nothing they do will make the images appear again besides doing a hard refresh of the page. This isn't ideal because they lose the state of the images they had open + any effects they've done to it like changing the brightness/contrast.

The big problem is this is happening silently. There are no errors or anything (that I know of) that are happening to cause this. The users are in clinical offices, so my hunch is that it is related to them leaving the website open for extended periods of time without touching the machine. I expect that their computers are going to sleep or the browser/system is cleaning up resources automatically since they aren't being used. I need help from anyone who is experienced with WebGL because I can't find any information on if this is a thing that can happen. The reason why I'm leaning towards this though is the WebGL stuff happens in "a different world" than the main thread it's the only thing that could disappear on it's own. Either way what the users are reporting is that it just goes black. It's failing silently with no errors. On my end I have no code that automatically does things on it's own. No code is messing with anything regarding the images/data array for the canvas/etc on it's own. It's only in response to user interactions. From what they are reporting it seems like there is no user interaction and that they just come back to the viewer being black.

Some of the images that are rendered aren't simple jpegs or pngs, they are DICOM files. These DICOM files can be very large from a few megabytes to hundreds. They can contain "slices" or "frames" so they have 100+ images inside them. The way it works in the viewer is the user can ctrl + mouse wheel to scroll through the slices/frames. Each one gets cached so that they can scroll back to previously viewed frames and it will instantly load. Most of this functionality is handled within the external library. From digging in the source code and reading the (very incomplete) docs for the external library, it automatically handles removing items from the cache when the memory usage hits a certain limit.

I cannot reproduce this behavior locally. There isn't any kind of client interactions like opening and closing images over and over + using different image manipulation tools that cause it to happen. Add this to there not being any kind of errors happening the only thing I have to work off of is assumptions.

My bandaid solution for now is I added an inactivity tracker where if the window receives no events after ~30 seconds you are considered "inactive" using Huntabyte's runed library https://runed.dev/docs/utilities/is-idle. When the user is considered idle/inactive it triggers a svelte
$effect()
that iterates over all open "viewports", gets the canvas context, then iterates over the imageData array and checks if every pixel is
0,0,0,255
(all black). If every pixel in the canvas is black it will force re-mount the svelte component for the viewer. This will ensure that the whole loading process starts fresh. I have all this logic in a
setInterval()
that repeats every 5 seconds. So while the user is idle it will monitor the open viewports to check if any of them randomly go black. I also have a condition for if the user becomes active again it will do that check one last time. This is because the user can go inactive, then become active again before the first
setInterval()
call runs.
Was this page helpful?