google / neuroglancer

WebGL-based viewer for volumetric data
Apache License 2.0
1.02k stars 283 forks source link

Neuroglancer hanging during Python tests involving volume rendering and screenshot/sync calls #580

Closed seankmartin closed 2 months ago

seankmartin commented 2 months ago

There could be something wrong with how I'm doing the test, but neuroglancer seems to hang if testing from Python using volume rendering. For example, the test below appears to get stuck when calling webdriver.sync.

import neuroglancer
import numpy as np

def test_max_projection(webdriver):
    def get_shader():
        return """
#uicontrol invlerp normalized(range=[0,1])
void main() {
    emitGrayscale(normalized());
}
"""

    with webdriver.viewer.txn() as s:
        s.dimensions = neuroglancer.CoordinateSpace(
            names=["x", "y", "z"], units="nm", scales=[1, 1, 1]
        )
        s.layers["image"] = neuroglancer.ImageLayer(
            source=neuroglancer.LocalVolume(
                np.zeros((10, 40, 50)), dimensions=s.dimensions
            ),
            volume_rendering_mode="MAX",
            shader=get_shader(),
        )
        s.layout = "3d"
        s.show_axis_lines = False
        s.show_default_annotations = False

    assert webdriver.viewer.state.layers["image"].volume_rendering_mode == "MAX"
    webdriver.sync()
    screenshot = webdriver.viewer.screenshot(size=[10, 10]).screenshot
    np.testing.assert_array_equal(
        screenshot.image_pixels,
        np.tile(np.array([0, 0, 0, 255], dtype=np.uint8), (10, 10, 1)),
    )

The test fails on timeout > 30s with a snippet of the log as:

test_max_projection.py:30: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../.tox/chrome/lib/python3.10/site-packages/neuroglancer/webdriver.py:224: in sync
    new_state = self.viewer.screenshot().viewer_state
../../.tox/chrome/lib/python3.10/site-packages/neuroglancer/viewer_base.py:161: in screenshot
    event.wait()
/usr/lib/python3.10/threading.py:607: in wait
    signaled = self._cond.wait(timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

The intention here would be to ensure that nothing is rendered in VR max projection with a volume of all 0s where 0 is mapped to a completely transparent output.