Repository: vispy/vispy

Issue:
Error drawing visual vispy visuals mesh.MeshVisual and vispy visuals tube.TubeVisual
I have upgraded vispy today to 0.6.0 and now I am not able to run this example
I am getting empty canvas screen and widgets box window.
https://github.com/vispy/vispy/blob/master/examples/demo/visuals/wiggly_bar.py


I got this error

WARNING: Error drawing visual <vispy.visuals.mesh.MeshVisual object at 0x7ff6540694a8>
WARNING:vispy:Error drawing visual <vispy.visuals.mesh.MeshVisual object at 0x7ff6540694a8>
WARNING: Traceback (most recent call last):
  File "wiggly_vispy.py", line 855, in <module>
    main()
  File "wiggly_vispy.py", line 851, in main
    win.show()
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/app/backends/_qt.py", line 501, in event
    out = super(QtBaseCanvasBackend, self).event(ev)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/app/backends/_qt.py", line 501, in event
    out = super(QtBaseCanvasBackend, self).event(ev)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/app/backends/_qt.py", line 818, in paintGL
    self._vispy_canvas.events.draw(region=None)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/util/event.py", line 455, in __call__
    self._invoke_callback(cb, event)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/util/event.py", line 475, in _invoke_callback
    self, cb_event=(cb, event))
  << caught exception here: >>
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/util/event.py", line 471, in _invoke_callback
    cb(event)
  File "wiggly_vispy.py", line 344, in on_draw
    vis.draw()
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/visuals/visual.py", line 595, in draw
    v.draw()
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/visuals/mesh.py", line 519, in draw
    Visual.draw(self, *args, **kwds)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/visuals/visual.py", line 443, in draw
    self._vshare.index_buffer)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/visuals/shaders/program.py", line 101, in draw
    Program.draw(self, *args, **kwargs)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/program.py", line 533, in draw
    canvas.context.flush_commands()
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/context.py", line 176, in flush_commands
    self.glir.flush(self.shared.parser)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 572, in flush
    self._shared.flush(parser)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 494, in flush
    parser.parse(self._filter(self.clear(), parser))
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 819, in parse
    self._parse(command)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 779, in _parse
    ob.draw(*args)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 1322, in draw
    gl.check_error('Check before draw')
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/gl/__init__.py", line 207, in check_error
    raise err
RuntimeError: OpenGL got errors (Check before draw): GL_INVALID_VALUE
WARNING:vispy:Traceback (most recent call last):
  File "wiggly_vispy.py", line 855, in <module>
    main()
  File "wiggly_vispy.py", line 851, in main
    win.show()
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/app/backends/_qt.py", line 501, in event
    out = super(QtBaseCanvasBackend, self).event(ev)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/app/backends/_qt.py", line 501, in event
    out = super(QtBaseCanvasBackend, self).event(ev)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/app/backends/_qt.py", line 818, in paintGL
    self._vispy_canvas.events.draw(region=None)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/util/event.py", line 455, in __call__
    self._invoke_callback(cb, event)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/util/event.py", line 475, in _invoke_callback
    self, cb_event=(cb, event))
  << caught exception here: >>
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/util/event.py", line 471, in _invoke_callback
    cb(event)
  File "wiggly_vispy.py", line 344, in on_draw
    vis.draw()
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/visuals/visual.py", line 595, in draw
    v.draw()
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/visuals/mesh.py", line 519, in draw
    Visual.draw(self, *args, **kwds)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/visuals/visual.py", line 443, in draw
    self._vshare.index_buffer)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/visuals/shaders/program.py", line 101, in draw
    Program.draw(self, *args, **kwargs)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/program.py", line 533, in draw
    canvas.context.flush_commands()
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/context.py", line 176, in flush_commands
    self.glir.flush(self.shared.parser)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 572, in flush
    self._shared.flush(parser)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 494, in flush
    parser.parse(self._filter(self.clear(), parser))
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 819, in parse
    self._parse(command)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 779, in _parse
    ob.draw(*args)
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/glir.py", line 1322, in draw
    gl.check_error('Check before draw')
  File "/home/kunnal/.local/lib/python3.5/site-packages/vispy/gloo/gl/__init__.py", line 207, in check_error
    raise err
RuntimeError: OpenGL got errors (Check before draw): GL_INVALID_VALUE
ERROR: Invoking <bound method WigglyBar.on_draw of <WigglyBar (PyQt5) at 0x7ff65455d9e8>> for DrawEvent
ERROR:vispy:Invoking <bound method WigglyBar.on_draw of <WigglyBar (PyQt5) at 0x7ff65455d9e8>> for DrawEvent
WARNING: Error drawing visual <vispy.visuals.mesh.MeshVisual object at 0x7ff6540694a8>
WARNING:vispy:Error drawing visual <vispy.visuals.mesh.MeshVisual object at 0x7ff6540694a8>
ERROR: Invoking <bound method WigglyBar.on_draw of <WigglyBar (PyQt5) at 0x7ff65455d9e8>> repeat 2
ERROR:vispy:Invoking <bound method WigglyBar.on_draw of <WigglyBar (PyQt5) at 0x7ff65455d9e8>> repeat 2
WARNING: Error drawing visual <vispy.visuals.tube.TubeVisual object at 0x7ff654048dd8>


Thanks for help




Discussion:
@kunnalparihar Thanks for the report. I got similar traceback using python 3.7. Unfortunately this demo isn't tested within the CI Framework. 

@djhoese Seems that also other Apps which use PyQt are broken (eg https://github.com/vispy/vispy/blob/master/examples/demo/gloo/primitive_mesh_viewer_qt.py)
Hm, I get the same results. For the mesh viewer example:

```
$ python examples/demo/gloo/primitive_mesh_viewer_qt.py
WARNING: Traceback (most recent call last):
  File "/Users/davidh/repos/git/vispy/vispy/app/backends/_qt.py", line 818, in paintGL
    self._vispy_canvas.events.draw(region=None)
  File "/Users/davidh/repos/git/vispy/vispy/util/event.py", line 428, in __call__
    raise RuntimeError('EventEmitter loop detected!')
RuntimeError: EventEmitter loop detected!
Abort trap: 6
```
For info, on my side, same error as the first one reported above for:
```
examples/demo/visuals/wiggly_bar.py
examples/demo/gloo/two_qt_widgets.py
```
However, `examples/demo/gloo/primitive_mesh_viewer_qt.py` seems to work without error.

Linux/Python 3.7
Yes, In my case also examples/demo/gloo/primitive_mesh_viewer_qt.py seems to work without error. Actual problem comes when I am using vispy.visuals with PyQt5 in latest version (0.6.0) of vispy.
@asnt @kunnalparihar @djhoese the output of `vispy.sys_info` would be interesting. And, we should try to narrow it down by simplifying the examples. 
@asnt @djhoese 
the output when I run vispy.sys_info. I have made it short. Do you need full output ?

"Platform: Linux-4.15.0-54-generic-x86_64-with-Ubuntu-16.04-xenial
Python: 3.5.2 (default, Nov 12 2018, 13:43:14)  [GCC 5.4.0 20160609]
NumPy:    1.16.2
Backend:  PyQt5
pyqt4:    None
pyqt5:    ('PyQt5', '5.12.2', '5.12.3')
pyside:   None
pyside2:  None
pyglet:   None
glfw:     glfw (3, 1, 2)
sdl2:     None
wx:       None
egl:      EGL 1.4 (DRI2) Mesa Project: OpenGL OpenGL_ES
osmesa:   OSMesa
_test:    None
GL version:  '3.0 Mesa 18.0.5'
MAX_TEXTURE_SIZE: 16384
Extensions: 'GL_3DFX_texture_compression_FXT1 GL_AMD_conservative_depth......
@kunnalparihar No, that will be sufficient. I doubt, that the Extensions have anything to do with it.

My current setup with vispy 0.6.0 from conda-forge.
```
Platform: Linux-4.12.14-lp150.12.64-default-x86_64-with-glibc2.10
Python:   3.7.3 | packaged by conda-forge | (default, Jul  1 2019, 21:52:21)  [GCC 7.3.0]
NumPy:    1.16.4
Backend:  PyQt5
pyqt4:    None
pyqt5:    ('PyQt5', '5.9.2', '5.9.7')
pyside:   None
pyside2:  None
pyglet:   None
glfw:     None
sdl2:     None
wx:       None
egl:      None
osmesa:   OSMesa
_test:    None

GL version:  '4.6.0 NVIDIA 390.87'
MAX_TEXTURE_SIZE: 16384
```
@djhoese For the meshviewer demo (https://github.com/vispy/vispy/blob/master/examples/demo/gloo/primitive_mesh_viewer_qt.py) it seems that vispy app event handling collides with pyqt event handling. If I change the canvas to scene.SceneCanvas then there is at least some output and the different meshes can be altered. I do not have the time to dig deeper, but something is fishy with the eventhandling.
On my side:
```
Platform: Linux-5.1.15-arch1-1-ARCH-x86_64-with-arch
Python:   3.7.3 (default, Jun 24 2019, 04:54:02)  [GCC 9.1.0]
NumPy:    1.16.4
Backend:  PyQt5
pyqt4:    None
pyqt5:    ('PyQt5', '5.12.3', '5.13.0')
pyside:   None
pyside2:  None
pyglet:   pyglet 1.4.0b1
glfw:     glfw (3, 3, 0)
sdl2:     None
wx:       None
egl:      EGL 1.4 Mesa Project: OpenGL OpenGL_ES
osmesa:   OSMesa
_test:    None

GL version:  '3.0 Mesa 19.1.1'
MAX_TEXTURE_SIZE: 16384
```
Ok major improvement on the mesh viewer: commenting out the fps measurement makes it work 100%. With it, on my newest python 3.7 conda-forge based environment with PyQt5 5.9, I get a lot of issues where the GL canvas won't draw and most times even the Qt widgets won't draw. This makes me think the FPS measurement is corrupting the GL context in some way or stopping Qt from drawing things (since all Widgets in Qt5 are GL based iirc). Will investigate further...
@kmuehlbauer I messaged you on gitter to see if you could look at the mesh viewer example for me and see if you see the same results. If you comment out the `showMessage` call in the `show_fps` method you should see that everything works as expected. If you print the FPS that's fine. If you use `showMessage` though it causes a recursive repaint event where `showMessage` starts a draw, which calls the measure fps callback, which results in `showMessage`, and so on. If you give it a message that doesn't change (a static string), Qt will "debounce" it and it works fine.

I tried to see if it was something specific to the QStatusBar that comes with the main widget by adding a QLabel to the widgets on the left of the Window and set the text on it instead of the status bar. This "works" but it causes a weird drawing effect where the mesh goes back and forth from the right size in the center of the canvas to a smaller size in the lower left. This may be a problem related to me having a HiDPI display (which makes me a little scared).

Basically, I can't tell if this is a bug in PyQt or bad practice by this example. I *think* it makes sense that `showMessage` repaints *everything*, especially given the little I understand about PyQt5 using OpenGL for all widgets. I'm wondering if we maybe put the measure fps callback *before* the regular draw callbacks (not sure we can do that with the way it disconnects/connects repeatedly) if that will fix things. I haven't tested that.

Here are my QLabel changes I tried as a test:

```
Index: examples/demo/gloo/primitive_mesh_viewer_qt.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- examples/demo/gloo/primitive_mesh_viewer_qt.py	(revision bfe96648fb50ec1eec56568aff93a302473a2e6f)
+++ examples/demo/gloo/primitive_mesh_viewer_qt.py	(date 1563848654247)
@@ -177,6 +177,8 @@
             # Signal
             self.sp[pos].valueChanged.connect(self.update_param)
 
+        self.fps_label = QtWidgets.QLabel("FPS: ...")
+        gb_c_lay.addWidget(self.fps_label, pos + 1, 0)
         self.gb_c.setLayout(gb_c_lay)
 
         vbox = QtWidgets.QVBoxLayout()
@@ -333,7 +335,9 @@
 
     def show_fps(self, fps):
         nbr_tri = self.mesh.n_faces
-        self.status.showMessage("FPS - %.2f and nbr Tri %s " % (fps, nbr_tri))
+        msg = "FPS - %0.2f and nbr Tri %s " % (float(fps), int(nbr_tri))
+        # self.status.showMessage(msg)
+        self.props_widget.fps_label.setText(msg)
 
     def update_view(self, param):
         cols = param.props['cols']
```
Oh and on the wiggly bar: so far if I comment out `on_draw` then it at least opens and shows the Qt widgets. I'm not a huge fan of the low level clear/draw calls in a higher level "visual" demo, but maybe it should still work.
@djhoese Your patch works fine for me too. While tracing the qt-docs I found [this](https://doc.qt.io/qt-5/qstatusbar.html#permanent-message):

_Normal and Permanent messages are displayed by creating a small widget (QLabel, QProgressBar or even QToolButton) and then adding it to the status bar using the addWidget() or the addPermanentWidget() function. Use the removeWidget() function to remove such messages from the status bar._

I tested this with the `self.status` on the main window and it worked like your implementation within the widget.

Basically I'm almost sure that using "showMessage" doesn't work because of roundtripping event queue and using it in this example might be bad. We should just change to the above advertised method using widgets in the statusbar.
> Oh and on the wiggly bar: so far if I comment out `on_draw` then it at least opens and shows the Qt widgets.

Same here, but no idea so far what to do and where to look.


@kmuehlbauer For the status bar, when you do either the extra widget (`addWidget`) or my patch, do you see the same flickering effect between a small mesh then a full size mesh?
@djhoese What  do you mean by small mesh vs. full size mesh.?
> This "works" but it causes a weird drawing effect where the mesh goes back and forth from the right size in the center of the canvas to a smaller size in the lower left. This may be a problem related to me having a HiDPI display (which makes me a little scared).

The mesh is drawn correctly for one or two frames, then it is shown as half the size and in the lower left, then back to proper size in the center, and so on.
OK, no, I do not experience these issues.

Resolving patch:
diff --git a/examples/demo/gloo/primitive_mesh_viewer_qt.py b/examples/demo/gloo/primitive_mesh_viewer_qt.py
--- a/examples/demo/gloo/primitive_mesh_viewer_qt.py
+++ b/examples/demo/gloo/primitive_mesh_viewer_qt.py
@@ -315,7 +315,8 @@ def __init__(self):
 
         # FPS message in statusbar:
         self.status = self.statusBar()
-        self.status.showMessage("...")
+        self.status_label = QtWidgets.QLabel('...')
+        self.status.addWidget(self.status_label)
 
         self.mesh = MyMeshData()
         self.update_view(self.props_widget.param)
@@ -333,7 +334,11 @@ def list_objectChanged(self):
 
     def show_fps(self, fps):
         nbr_tri = self.mesh.n_faces
-        self.status.showMessage("FPS - %.2f and nbr Tri %s " % (fps, nbr_tri))
+        msg = "FPS - %0.2f and nbr Tri %s " % (float(fps), int(nbr_tri))
+        # NOTE: We can't use showMessage in PyQt5 because it causes
+        #       a draw event loop (show_fps for every drawing event,
+        #       showMessage causes a drawing event, and so on).
+        self.status_label.setText(msg)
 
     def update_view(self, param):
         cols = param.props['cols']
diff --git a/examples/demo/visuals/wiggly_bar.py b/examples/demo/visuals/wiggly_bar.py
--- a/examples/demo/visuals/wiggly_bar.py
+++ b/examples/demo/visuals/wiggly_bar.py
@@ -263,7 +263,8 @@ def __init__(self, d1=None, d2=None, little_m=None, big_m=None,
 
         """
 
-        app.Canvas.__init__(self, title='Wiggly Bar', size=(800, 800))
+        app.Canvas.__init__(self, title='Wiggly Bar', size=(800, 800),
+                            create_native=False)
 
         # Some initialization constants that won't change
         self.standard_length = 0.97 + 0.55
@@ -288,10 +289,10 @@ def __init__(self, d1=None, d2=None, little_m=None, big_m=None,
 
         # Put up a text visual to display time info
         self.font_size = 24. if font_size is None else font_size
-        self.text = visuals.TextVisual('0:00.00', 
-                                       color='white', 
+        self.text = visuals.TextVisual('0:00.00',
+                                       color='white',
                                        pos=[50, 250, 0],
-                                       anchor_x='left', 
+                                       anchor_x='left',
                                        anchor_y='bottom')
         self.text.font_size = self.font_size
 
@@ -299,17 +300,17 @@ def __init__(self, d1=None, d2=None, little_m=None, big_m=None,
         # update this
         self.method_text = visuals.TextVisual(
             'Method: {}'.format(self.method),
-            color='white', 
-            pos=[50, 250 + 2/3*font_size, 0],
-            anchor_x='left', 
+            color='white',
+            pos=[50, 250, 0],
+            anchor_x='left',
             anchor_y='top'
         )
         self.method_text.font_size = 2/3 * self.font_size
 
         # Get the pivoting bar ready
-        self.rod = visuals.BoxVisual(width=self.px_len/40, 
-                                     height=self.px_len/40, 
-                                     depth=self.px_len, 
+        self.rod = visuals.BoxVisual(width=self.px_len/40,
+                                     height=self.px_len/40,
+                                     depth=self.px_len,
                                      color='white')
         self.rod.transform = transforms.MatrixTransform()
         self.rod.transform.scale(
@@ -371,7 +372,6 @@ def __init__(self, d1=None, d2=None, little_m=None, big_m=None,
 
         # Set up a timer to update the image and give a real-time rendering
         self._timer = app.Timer('auto', connect=self.on_timer, start=True)
-        self.show()
 
     def on_draw(self, ev):
         # Stolen from previous - just clears the screen and redraws stuff
@@ -379,7 +379,7 @@ def on_draw(self, ev):
         self.context.set_viewport(0, 0, *self.physical_size)
         self.context.clear()
         for vis in self.visuals:
-            if vis == self.center_point and not self.show_pivot:
+            if vis is self.center_point and not self.show_pivot:
                 continue
             else:
                 vis.draw()
@@ -453,7 +453,7 @@ def on_timer(self, ev):
                                           self.s2_loc +
                                           np.asarray([delta_x, 0]))
 
-        # Redraw and rescale the lower spring 
+        # Redraw and rescale the lower spring
         # (the hardest part to get, mathematically)
         self.spring_1.transform.reset()
         self.spring_1.transform.rotate(90, (0, 1, 0))
@@ -469,8 +469,8 @@ def on_timer(self, ev):
         self.mass.transform.translate(self.center + self.mass_loc)
 
         # Update the timer with how long it's been
-        self.text.text = '{:0>2d}:{:0>2d}.{:0>2d}'.format(min_passed, 
-                                                          sec_passed, 
+        self.text.text = '{:0>2d}:{:0>2d}.{:0>2d}'.format(min_passed,
+                                                          sec_passed,
                                                           millis_passed)
 
         # Trigger all of the drawing and updating


Test patch: