Skip to content

Initial steps to move away from deprecated OpenGL functionality#1530

Merged
David-Baddeley merged 39 commits into
python-microscopy:masterfrom
David-Baddeley:glcore
Jul 31, 2024
Merged

Initial steps to move away from deprecated OpenGL functionality#1530
David-Baddeley merged 39 commits into
python-microscopy:masterfrom
David-Baddeley:glcore

Conversation

@David-Baddeley
Copy link
Copy Markdown
Contributor

PYMEVis has been using the old, deprecated, compatibility profile within OpenGL. This is a first step towards getting stuff working on the more modern "core" profile. To some extent this is an exercise in learning modern OpenGL, as a prelude for doing some WebGL stuff, but should also be good for PYMEVis in the long term.

The main advantages are:

  • hopefully better platform support
  • possible (small) speed increases
  • future proofing
  • making a hypothetical webgl port easier

Still very much a work in progress, but points, spheres, and pointsprites work (modulo potential point scaling changes). Pretty much all the other layers don't work yet (surfaces, overlays, scalebars etc ...).

To run, use PYMEVis --opengl-core-profile

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

Now almost there - just missing text overlays (and labels).

In the process I've found and hit a few bugs:

  • points have been rendering the wrong size on high DPI displays (retina and the like) - Fixed
  • point size is capped by hardware (to 64 pixels on my mac), which means that point scaling messes up when zoomed in. This might be tricky to fix. Not a major issue for most of my use cases, but potentially problematic for people using pointsprites as a display output.

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

@csoeller, @zacsimile

Should now be almost complete (modulo removing a timing debug statement) if either of you are interested in testing. Particularly interested in testing on non-mac platforms. Aside from just getting it somewhere where we can use modern opengl, there are 2 changes that are actually attractive from a usage point of view:

  • fixing point sizes on high dpi screens (still need to double-check for point-sprites)
  • a 2-3 fold speed improvement when manipulating large mesh datasets.

@csoeller
Copy link
Copy Markdown
Contributor

Very nice, will try next week, currently travelling. I will also be able to try windows platforms then. I had noticed the bugs in the past but had assumed that these are things not easy to work around.

Does the buggy behaviour include the observation that I generally make, when I zoom in hard, that the apparent distances between points appear to increase beyond a certain point? If I recall correctly they appear to increase relative to scale bar size and also in all rendering modes, definitely seen it with sphere rendering.

I also noticed that sphere diameter scale seemed to be off on some displays, maybe high res as you say.

Hopefully all of these will be fixed with the new code, looking forward to trying it.

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

Unfortunately the point size cap hasn't been fixed (yet) - just the scaling on high dpi screens. Point size cap (currently maxes out at 64 pixels on mac, which is not very large) is going to be a bit harder to address, but hopefully doable.

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

That was actually easier than anticipated - point size scaling now works as expected for the 3 main display types.

Now need to decide whether to use the quad based rendering for all points (even small ones) rather than switching over when needed, as there doesn't seem to be much (if any) penalty and it would lead to cleaner code.

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

@barentine - should probably loop you into this as well - it's going to mean a little extra work for #1520, but shouldn't be too bad (mainly changing the glVertexPointer(...) etc calls for self._bind_data(...) ones.

I'm inclined to move using the modern opengl interface by default pretty quickly as it addresses a couple of long-standing and slightly embarrassing issues with point sizing.

@csoeller
Copy link
Copy Markdown
Contributor

Turns out I wasn't using the flag --opengl-core-profile in my initial tests. The issues above are therefore with the older profile. The LUT display issue when loading a saved session looks the same though with the flag as shown in my previous comments.

Upon further tests, now with the flag, all on mac:

  • points and point_sprites seem to work nicely
  • transparent_points come up as squares, not circles
  • shaded_points do not work properly and generate DEBUG:PYME.LMVis.layers.pointcloud:No big point shader class defined, using default shader - points will appear smaller than expected
  • sometimes, when switching back from shaded_points to transparent_points, this then suffers from the same issue (tiny dots), until switching through points or point_sprites and then back to transparent_points which fixes things (still squares though)

Transparent points:

Screenshot 2024-07-29 at 21 47 19

Transparent points after changing from shaded points:

Screenshot 2024-07-29 at 21 47 53

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

Thanks!

Transparent and shaded points are not a big surpise as I haven't touched them yet (being not well used). The LUT thing is something I saw briefly, but couldn't reliably reproduce ... maybe the saved sessions might be a way to do so ...

@csoeller
Copy link
Copy Markdown
Contributor

Cool, transparent points work now, nice. Session saving seems broken in the latest iteration:

 Error whilst running File>Save Session
==============================================
python-microscopy=23.06.15.post0.dev[git]
python=3.10.13, platform=darwin
numpy=1.26.4, wx=4.2.1 osx-cocoa (phoenix) wxWidgets 3.2.2.1

Traceback
=========
Traceback (most recent call last):
  File "/Users/csoe002/Documents/src/PYMEsrc/PYME-test-env/build-test-py3.10-conda_1/python-microscopy-python-310-compat/PYME/ui/progress.py", line 153, in func
    return fcn(*args, **kwargs)
  File "/Users/csoe002/Documents/src/PYMEsrc/PYME-test-env/build-test-py3.10-conda_1/python-microscopy-python-310-compat/PYME/LMVis/visCore.py", line 846, in OnSaveSession
    self.save_session(filename)
  File "/Users/csoe002/Documents/src/PYMEsrc/PYME-test-env/build-test-py3.10-conda_1/python-microscopy-python-310-compat/PYME/LMVis/visCore.py", line 838, in save_session
    f.write(self.get_session_yaml())
  File "/Users/csoe002/Documents/src/PYMEsrc/PYME-test-env/build-test-py3.10-conda_1/python-microscopy-python-310-compat/PYME/LMVis/visCore.py", line 833, in get_session_yaml
    session.update(self.glCanvas.get_session_info())
AttributeError: 'LMGLShaderCanvas' object has no attribute 'get_session_info'

Also, I noticed (not sure if always or only sometimes), that spheres become oblong when zooming in hard, screenshot below, all on mac:

Screenshot 2024-07-30 at 11 11 24

I hope it is ok to keep posting my observations, perhaps you are already aware of some.

@csoeller
Copy link
Copy Markdown
Contributor

Also, no luck yet on windows (win11) when starting pymevis with the flag --opengl-core-profile...

...
OpenGL - Version: b'4.6.0 Compatibility Profile Context 23.40.02.240110'
Shader - Version: 460
GL.GL_MAX_SAMPLES: 8, GL.GL_SAMPLES: 4
DEBUG:PYME.LMVis.shader_programs.ShaderProgramFactory:New shader program created: <class 'PYME.LMVis.shader_programs.DefaultShaderProgram.DefaultShaderProgram'>
DEBUG:PYME.LMVis.shader_programs.ShaderProgramFactory:New shader program created: <class 'PYME.LMVis.shader_programs.DefaultShaderProgram.ImageShaderProgram'>
dict_keys([<class 'numpy.ndarray'>, <class 'bytes'>, <class 'OpenGL.converters.c_long_Array_1'>, <class 'NoneType'>, <class 'ctypes.c_void_p'>])
Traceback (most recent call last):
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\latebind.py", line 43, in __call__
    return self._finalCall( *args, **named )
TypeError: 'NoneType' object is not callable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:\pyt\pte\build-test-py3.10-mamba_1\python-microscopy-master\PYME\LMVis\glcanvas_core.py", line 225, in OnPaint
    self.OnDraw()
  File "c:\pyt\pte\build-test-py3.10-mamba_1\python-microscopy-master\PYME\LMVis\glcanvas_core.py", line 480, in OnDraw
    self.ScaleBarOverlayLayer.render(self)
  File "c:\pyt\pte\build-test-py3.10-mamba_1\python-microscopy-master\PYME\LMVis\layers\ScaleBarOverlayLayer.py", line 93, in render
    self._bind_data('scalebar', self._verts, 0*self._verts, self._cols, sp, core_profile=core_profile)
  File "c:\pyt\pte\build-test-py3.10-mamba_1\python-microscopy-master\PYME\LMVis\layers\base.py", line 123, in _bind_data
    return self._bind_data_core(name, vertices, normals, colors, sp)
  File "c:\pyt\pte\build-test-py3.10-mamba_1\python-microscopy-master\PYME\LMVis\layers\base.py", line 77, in _bind_data_core
    glDeleteVertexArrays(1, old_vao)
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\latebind.py", line 47, in __call__
    return self._finalCall( *args, **named )
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\wrapper.py", line 689, in wrapperCall
    pyArgs = tuple( calculate_pyArgs( args ))
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\wrapper.py", line 450, in calculate_pyArgs
    yield converter(args[index], self, args)
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\converters.py", line 135, in __call__
    return self.function( incoming )
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\arrays\arraydatatype.py", line 154, in asArray
    return cls.getHandler(value).asArray( value, typeCode or cls.typeConstant )
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\arrays\arraydatatype.py", line 56, in __call__
    raise TypeError(
TypeError: ('No array-type handler for type numpy.uintc (value: 2) registered', <OpenGL.converters.CallFuncPyConverter object at 0x000002556F11B610>)
dict_keys([<class 'numpy.ndarray'>, <class 'bytes'>, <class 'OpenGL.converters.c_long_Array_1'>, <class 'NoneType'>, <class 'ctypes.c_void_p'>])
dict_keys([<class 'numpy.ndarray'>, <class 'bytes'>, <class 'OpenGL.converters.c_long_Array_1'>, <class 'NoneType'>, <class 'ctypes.c_void_p'>])
Traceback (most recent call last):
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\latebind.py", line 43, in __call__
    return self._finalCall( *args, **named )
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\wrapper.py", line 689, in wrapperCall
    pyArgs = tuple( calculate_pyArgs( args ))
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\wrapper.py", line 450, in calculate_pyArgs
    yield converter(args[index], self, args)
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\converters.py", line 135, in __call__
    return self.function( incoming )
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\arrays\arraydatatype.py", line 154, in asArray
    return cls.getHandler(value).asArray( value, typeCode or cls.typeConstant )
  File "C:\Users\soeller\AppData\Local\miniforge3\envs\test-pyme-3.10-mamba_1\lib\site-packages\OpenGL\arrays\arraydatatype.py", line 56, in __call__
    raise TypeError(
TypeError: ('No array-type handler for type numpy.uintc (value: 2) registered', <OpenGL.converters.CallFuncPyConverter object at 0x000002556F11B610>)

During handling of the above exception, another exception occurred:

.....

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

Many thanks!

Should have (hopefully) fixed session loading and saving - and the LUT bug.

The squashed points is likely to be an aspect ration issue (which I thought I had already addressed) - Points bigger than the max supported point size are actually drawn as rectangles and then made to look like points using some magic in the fragment shader.

What is your pyopengl version on windows? On Linux I needed to update the pyopengl version to 3.1.5 to avoid similar issues.

@csoeller
Copy link
Copy Markdown
Contributor

On windows it is running pyopengl 3.1.6. Looks like I cannot easily upgrade from that with conda, could try pip though. Note everything is with Python 3.10 which I run for production work now.

Will try the session stuff soonish...

@csoeller
Copy link
Copy Markdown
Contributor

Ok, saves and loads sessions now ok on mac, LUTs look ok too now.

The (experimental) text layer nearly works, currently colouring makes it appear a bit weird, suggesting it is the LUT mapping that needs a little tweak. Otherwise looking good!

Screenshot 2024-07-30 at 14 12 00

@csoeller
Copy link
Copy Markdown
Contributor

...on windows no luck yet, tried pyopengl 3.1.5., 3.1.6 and 3.1.7. Always same error as above....

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

should now be fixed on windows (fingers crossed ...), although windows does not work without the --opengl-core-profile flag. Not sure if that is worth fixing / hacking around or if we should just go all in on core profile now and not look back. Probably safe to go all in, as the feature set we are currently using with --opengl-core-profile was introduced in 2010.

@csoeller
Copy link
Copy Markdown
Contributor

I did only a 5 min test on windows, so far looking good (win11). What else should one test, a few more windows systems? I could probably try a few win10 machines as well...

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

Many thanks!
I managed to borrow a windows 10 machine to check in on, and it ran without issues.

I think this is probably now at the point where we can merge and deal with anything else that crops up as it appears.

I've switched it so that core profile is now the default, but you can (for now) get the old mode by running with --opengl-compatibility-profile.

@David-Baddeley David-Baddeley marked this pull request as ready for review July 31, 2024 21:50
@David-Baddeley David-Baddeley merged commit 5b95f15 into python-microscopy:master Jul 31, 2024
@csoeller
Copy link
Copy Markdown
Contributor

csoeller commented Aug 1, 2024

Many thanks, this is indeed looking pretty good now and I will use in production work, so that any issues should show up sooner than later.

Just for my understanding, with pointsprites after zooming in to some extent I still get the familiar smaller point size and debug messages of the type:

DEBUG:PYME.LMVis.layers.pointcloud:No big point shader class defined, using default shader - points will appear smaller than expected

Is this still expected to happen? This is on higher res displays (I think retina on the macbook and a fairly highish res monitor).

In practice for me it is still a little bit annoying as I am looking for small features in the data and really hope to still get the "blurring effect" of the point sprites. But maybe this is a tough thing to implement?

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

That's super frustrating - point-sprite scaling was working yesterday morning - might be an aspect-ratio linked regression.

@David-Baddeley
Copy link
Copy Markdown
Contributor Author

should be resolved with #1532

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants